ãŠã«ãã©ã¯ã€ãã«8çªãäžçºæŽå â Swift+AppleScript åæã«ãŒããš5ã€ã®çœ
ååãç°å¢ã®å£åãèªåæ€ç¥ããè©±ãæžããŸãããä»åã¯ãã£ãšå°å³ãªè©±ã§ã ââ ãŠã«ãã©ã¯ã€ãã¢ãã¿ã«æ£ããã£ãTerminalçª8æããã³ãã³ã1çºã§4x2ã°ãªããã«æããã¹ã¯ãªããã®èšèšã§ãã
~/.claude/scripts/terminal-grid8.sh ãå©ãã ãã§ã3440x1440ã®ç»é¢äžã®Terminalçªã x=0/860/1720/2580 ã®4åãäžæ®µã»äžæ®µã®2è¡ã«ãã£ã¡ãæããŸããäžèº«ã¯Swift 15è¡ïŒAppleScript 60è¡çšåºŠã®å°ããã¹ã¯ãªããã§ããã座æšç³»ã®å€æãšAppleScriptã®çªæäœç¹æã®çœ ãè©°ãŸã£ãŠããŠãçŽ æŽã«æžããšå¿
ãã©ããã§è©°ãŸããŸãã
å°ãããšïŒtell application "System Events" ã§çªãåãããšå¹³æ°ã§åãã€ã
AppleScriptã§ set position of window i to {x, y} ãåŒã¹ã°çªã¯åããŸããããããã8çªã¶ãforeachã§åããšã
- äžéšã®çªã ãåããªãïŒãšã©ãŒã¯åºãªãïŒ
- åããã¯ãã®çªãæ°ãã¬ãŒã åŸã«å ã®å Žæãžæ»ã
- 2åšç®ã«çªã®ååã§åç §ããããšãããããããªçªã¯ç¡ãããšèšããã
ãšãã£ãçŸè±¡ãèµ·ããŸããåå ã¯Terminalã®çªåãã¹ãããŒæåïŒâ â â³ãªã©ïŒãå«ãã§å®è¡äžã«å€ããç¶ããããšãsize ãš position ãåæã«æå®ãããšçæ¹ãç¡èŠãããããšãè¡åäœã§é«ããäžžãŸãããšãªã©ãAppleScriptè¶ãã«Terminalãæäœãããšãã ãåºãåå¥ã®çœ ã§ããããã1ã€ãã€åé¿ããªãããæªé
眮ã®çªãç¡ããªããŸã§åããç¶ãããèšèšã«ããã®ãä»åã®ã¹ã¯ãªããã§ãã
èšèš1ïŒCocoa座æš(å·Šäžåç¹)ãã°ããŒãã«åº§æš(å·Šäžåç¹)ã«å€æããŠã·ã§ã«ãžæž¡ã
察象ç»é¢ã®ç©åœ¢ãåãã®ã«ãAppleScriptã§ã¯ãªãSwiftã䜿ã£ãŠããŸããNSScreen.visibleFrame ãDockãšã¡ãã¥ãŒããŒãé€ããäœæ¥é åãè¿ããŠãããããã§ãããCocoaã®åº§æšç³»ã¯å·Šäžåç¹ã»Y軞äžåãã§ãAppleScriptã® position of window ã¯å·Šäžåç¹ã»Y軞äžåãã®ã°ããŒãã«åº§æšã§ããããã倿ãæãªããšãçªãç»é¢ã®éåŽã«é£ã³ãŸãã
import AppKit
let screens = NSScreen.screens
guard let main = screens.first else { exit(1) }
// æã暪é·ã®ç»é¢ã察象ã«ãã(ãŠã«ãã©ã¯ã€ã)ãåçãªãã¡ã€ã³ä»¥å€ãåªå
let target = screens.max(by: { $0.frame.width < $1.frame.width })!
let v = target.visibleFrame // Docké€å€(Cocoa座æš: å·Šäžåç¹Yäžåã)
let mainH = main.frame.height
var topY = mainH - (v.origin.y + v.height) // ã°ããŒãã«(å·Šäžåç¹)座æšãžå€æ
var h = v.height
// visibleFrameãã¡ãã¥ãŒããŒãåæ ããªãç»é¢ããã(宿ž¬: AXã¯top+30ã«ã¯ã©ã³ã)âæåã§å·®ãåŒã
if v.height == target.frame.height {
topY += 30
h -= 30
}
print("\(Int(v.origin.x)) \(Int(topY)) \(Int(v.width)) \(Int(h))")
mainH - (v.origin.y + v.height) ãå€æã®æ žã§ããã¡ã€ã³ç»é¢ã®é«ããããCocoa座æšã§ã®ãvisibleFrameã®äžç«¯ããåŒãããšã§ãAppleScriptåŽãæåŸ
ããã°ããŒãã«Y座æšãåºãŸãããã®4å€ãã¹ããŒã¹åºåãã§æšæºåºåã«æµããã·ã§ã«åŽã§åããŸãã
GEOM=$(swift - <<'EOF'
...
EOF
)
read -r GX GY GW GH <<< "$GEOM"
Swiftã® swift - ïŒæšæºå
¥åããheredocã§ã¹ã¯ãªãããæµã蟌ã圢ïŒã§ã³ã³ãã€ã«ç¡ãã«å®è¡ããçµæãã·ã§ã«å€æ°ã«å±éããããšããã®ãSwiftãšã·ã§ã«ã®æ©æž¡ãæ¹æ³ã§ããããã§ã»ã«å¹
ã»ã»ã«é«ïŒCW=$(( GW / COLS ))ïŒãèšç®ããŠãããosascriptã«åŒæ°ãšããŠæž¡ããŸãã
NSScreen.visibleFrameã¯ãã¡ãã¥ãŒããŒãé€ããé åãã®ã¯ãã§ããã宿ž¬ã§ã¯ç»é¢ã«ãã£ãŠã¡ãã¥ãŒããŒã¶ããåæ ãããvisibleFrame.height == frame.heightã«ãªãã±ãŒã¹ããããŸããã座æšå€æã¯äžçºã§ä¿¡çšãããæ¢ç¥ã®ç»é¢ã ãã§ã宿ž¬ã§æ€ç®ããã®ãå®å šã§ãã
èšèš2ïŒforeachã§ã¯ãªããæªé 眮çªãæ®ãéã1æã ãåãããŠåã¹ãã£ã³ãã®åæã«ãŒã
çªã®ãªã¹ããäžåºŠååŸããŠforeachã§åããããšããçŽ æŽãªå®è£ ã¯ç Žç¶»ããŸããçç±ã¯ãçªã®ååãã¹ãããŒã§å€±å¹ããããåãããçªã®indexãåçã«å€ãããããã§ããããã§ãã®ã¹ã¯ãªããã¯ãæ¯ãã¹ã§çªãåã¹ãã£ã³ããæªé 眮ã®çªã1æã ãèŠã€ããŠåããããŸãæåããã¹ãã£ã³ãçŽããšããåæã«ãŒãã«ããŠããŸãã
repeat with pass from 1 to (nCells * 3)
set occupied to {}
repeat nCells times
set end of occupied to false
end repeat
set moverIdx to 0
set n to count windows
-- 1) 察象ç»é¢äžã®çªãèµ°æ»ããã»ã«äžèŽæžã¿ãããŒã¯ã»æåã®æªé
眮çªãèšé²
repeat with i from 1 to n
try
set p to position of window i
set px to item 1 of p
set py to item 2 of p
on error
set px to -99999
set py to -99999
end try
if px ⥠(gx - tol) and px < (gx + nCols * cw) and py ⥠(gy - tol) and py < (gy + nRows * ch) then
set matched to false
repeat with k from 1 to nCells
if (not (item k of occupied)) and (px - (item k of cellX)) < tol and ((item k of cellX) - px) < tol and (py - (item k of cellY)) < tol and ((item k of cellY) - py) < tol then
set item k of occupied to true
set matched to true
exit repeat
end if
end repeat
if (not matched) and moverIdx = 0 then set moverIdx to i
end if
end repeat
-- 2) æªé
眮çªãç¡ããã°åæ
if moverIdx = 0 then exit repeat
...
ãã€ã³ãã¯3ã€ã§ãã
- ãã»ã«ã«äžèŽããŠããçªãã蚱容誀差
tol = 40pxã§ããŒã¯ãããã以å€ã§æåã«èŠã€ãã£ã1æã ããmoverIdxã«å ¥ãã - æªé
眮çªïŒ
moverIdx = 0ïŒãç¡ããªã£ãæç¹ã§ã«ãŒããæãã ââ ãããåææ¡ä»¶ - ã«ãŒãäžéã¯
nCells * 3ãã¹ãçè«äžã¯åçªã1ãã¹ã§1ã»ã«ã«åãŸãã®ã§nCellsãã¹ã§ååã§ãããéæž¡ãšã©ãŒïŒåŸè¿°ïŒã®ãªãã©ã€ã¶ãã«äœè£ãæãããŠããŸã
foreachã§å šçªãäžæ°ã«åããèšèšã ãšã1åšç®ã®éäžã§indexããºã¬ããåååç §ã倱å¹ãããããŠäºæ ããŸããã1åã®ã¹ãã£ã³ã«ã€ã1æã ãé²ããŠãæ¯åç¶æ ãèªã¿çŽãããšããã²ãŒã ã«ãŒãçãªèšèšã«ããããšã§ãéäžã§äœãèµ·ããŠã次ã®ãã¹ã§èŸ»è€ãåã圢ã«ããŠããŸãã
5ã€ã®å®è£ çœ
ã¹ã¯ãªããèªèº«ã®ã³ã¡ã³ããšã察å¿ããskillïŒ~/.claude/skills/auto/terminal-grid8-tiling/SKILL.mdïŒã«ãåå®è£
ããªãããã®ç¥èããšããŠæžãæ®ããŠãããã®ã§ãã
- çªã®åååç §ã¯ã¹ãããŒ(â â â³)å転ã§å€±å¹ãã â ååã§ã¯ãªãæ¯ãã¹indexã§åã¹ãã£ã³ãããã®å Žã§å³æäœãããååããã£ãã·ã¥ããŠåŸãã䜿ãèšèšã¯äºæ ã
sizeèšå®ã®çŽåŸã«positionãèšå®ãããšãdelayç¡ãã ãšç¡èŠãããïŒãšã©ãŒãåºãªãïŒ âset sizeâdelay 0.2âset positionâdelay 0.2â å床set sizeã®é ã«ãéãžå¿ ãdelay 0.2ãæããããã«èªã¿è¿ããŠè£æ£ãã
try
set size of window moverIdx to {cw, ch}
delay 0.2
set position of window moverIdx to {tx, ty}
delay 0.2
set size of window moverIdx to {cw, ch}
delay 0.2
-- èªã¿è¿ã㊠position ãæçµè£æ£(ãªãµã€ãºã§ã®ããªãã察ç)
set p2 to position of window moverIdx
if (item 1 of p2) is not tx or (item 2 of p2) is not ty then
set position of window moverIdx to {tx, ty}
delay 0.2
end if
on error
delay 0.3 -- ã¹ãããŒçã®éæž¡ãšã©ãŒã¯æ¬¡ãã¹ã§å詊è¡
end try
- Terminalã®é«ãã¯è¡åäœã«äžžãŸããããæå®ãã
chãŽã£ããã«ã¯ãªãããã»ã«é«ãè¶ éããåãmacOSã®ã¯ã©ã³ãã§åžåãããããããªãã£ããããŠãçªããšã«yããã©ã€ã â åæã«ãŒããæããåŸã«ãæäžæ®µã®çªã ãå®éã®é«ã(size)ãèªã¿çŽããŠäžç«¯æãã«æ£èŠåãããã¹ãå¥éèµ°ããã
-- æäžæ®µyã®æ£èŠå: å®é«(è¡äžžãã§ã»ã«é«ãè¶
ãã)ã®ã¯ã©ã³ãæºãã§ y ãæ··åšããããã
-- å®é«ãèªã¿åã£ãŠäžç«¯æãã«çµ±äžãã
set bottomEdge to gy + nRows * ch
set lastRowTop to gy + (nRows - 1) * ch
repeat with i from 1 to (count windows)
try
set p to position of window i
...
if px ⥠(gx - tol) and px < (gx + nCols * cw) and py ⥠(lastRowTop - tol) and py < bottomEdge then
set s to size of window i
set wh to item 2 of s
set targetY to bottomEdge - wh
...
visibleFrameãã¡ãã¥ãŒããŒã¶ããåæ ããªãç»é¢ããã â SwiftåŽã§v.height == target.frame.heightãæ€ç¥ãããtopY += 30; h -= 30ãšæåã§æ§é€ããïŒåæ²ã³ãŒãïŒ- éæž¡ãšã©ãŒïŒAppleScriptã®ãšã©ãŒçªå· -10006 / -1728 ãªã©ïŒã§tryãããã¯ãèœã¡ã â catchããŠãã®ãã¹ã¯è«Šãã
delay 0.3ãæãã§æ¬¡ãã¹ã«å§ãããåæã«ãŒããªã®ã§1ãã¹å€±æããŠãæ¬¡ã§æŸãçŽããèšèšãå¹ããŠãã
æ€èšŒã¯ãæçµã¬ããŒãã®åº§æšãæåŸ å€ã«æã£ãŠãããã§èŠãŸãã
- 察象: æã暪é·ã®ç»é¢(ãŠã«ãã©ã¯ã€ã)äžã®Terminalçª
- åºå: åçªã® x,y WxH ã¿ã€ãã«
- æ€èšŒ: xã 0/860/1720/2580 ã®4å€ãyãäžæ®µã»äžæ®µã®å1å€ã«æã£ãŠããã°æå
ãŸãšã
- 座æšç³»ã®æ©æž¡ãã¯Swiftã§
NSScreenããåããCocoa座æš(å·Šäžåç¹)ãã°ããŒãã«åº§æš(å·Šäžåç¹)ã«å€æããŠããã·ã§ã«å€æ°ãžæž¡ããvisibleFrameã¯ã¡ãã¥ãŒããŒæ¬ æã宿ž¬ã§çã - è€æ°çªã®äžæ¬æŽåã¯foreachã§ã¯ãªãåæã«ãŒãã«ããããæªé 眮çªãæ®ãéã1æã ãåãããŠæ¯ãã¹åã¹ãã£ã³ããAppleScriptã®çªåç §å€±å¹ã»indexãºã¬ã«åŒ·ã
- AppleScriptç¹æã®çœ ïŒã¹ãããŒå倱å¹ã»sizeçŽåŸã®positionç¡èŠã»è¡é«äžžãã®ã¯ã©ã³ãæºãïŒã¯ãdelay+èªã¿è¿ãè£æ£ãšäºåŸã®æ£èŠåãã¹ã§ããããæœ°ã
- éæž¡ãšã©ãŒã¯æ¡ãã€ã¶ããŠæ¬¡ãã¹ã«è³ããã1åã§å®ç§ãçãããåæãããŸã§ç¹°ãè¿ãèšèšã«ãã
次åã¯ããã®æã®ã¹ã¯ãªãããå«ãèªåå矀ãã©ãã¹ãã«åããŠè¿·åã«ãªããªãããã«ããŠããã ââ èªå·±å¢æ®ãããšãŒãžã§ã³ãç°å¢ã®è©±ãæžããŸãã
LilyïŒ@bokuwalilyïŒâ å人éçºè ãClaude Code ã§èªåååºç€ãçµã¿ãªãããiOSã¢ããªãWebãµãŒãã¹ãéç£ããŠããŸã
- AIã§ãå¯ãŠãŠãåãä»çµã¿ããäœã£ãŠæ120äžã«ãã話㯠noteã®ææèšäº ã«ð°
- OSS: github.com/bokuwalily ð
- ææ°æ å ±ã»ãåãåãã㯠X @bokuwalily ãžð
- AIå°å ¥ã»èªååã®çžè«ãšå®è£ ãã³ãã¬7æ¬ã®é åžã¯ å ¬åŒLINE ããð¬
çããã® â€ïž ãã·ã§ã¢ãå±ã¿ã«ãªããŸãïŒ