Skip to content

Instantly share code, notes, and snippets.

@frankpf
Created January 17, 2022 19:02
Show Gist options
  • Save frankpf/6b60040643a1bddbe2413f89526d2137 to your computer and use it in GitHub Desktop.
Save frankpf/6b60040643a1bddbe2413f89526d2137 to your computer and use it in GitHub Desktop.
Phoenix.set({
openAtLogin: true,
})
Key.on('return', ['option'], () => {
createTerminal()
})
Key.on('y', ['option'], () => {
Modal.build({
text: 'aaz',
origin: { x: 120, y: 120 },
duration: 20,
}).show()
})
// Focus right window
Key.on('l', ['option'], () => {
const window = currentWindow()
const {width: screenWidth} = Screen.main().visibleFrame()
const {x, y} = window.topLeft()
const {width: windowWidth} = window.size()
const end = x + windowWidth
// Try to find a window to the right of {end}
let otherWindow = undefined
for (let i = 1; i < (screenWidth-end); i = i + 10) {
Phoenix.log(`trying ${i} at ${end+i}, ${y}`)
const w = Window.at({ x: end + i, y: y + 10 })
if (w !== undefined && w.app().name() !== 'Finder') {
otherWindow = w
break
}
}
if (otherWindow === undefined) {
return
}
otherWindow.focus()
})
// Focus left window
Key.on('h', ['option'], () => {
const window = currentWindow()
const {width: screenWidth} = Screen.main().visibleFrame()
const {x, y} = window.topLeft()
const {width: windowWidth} = window.size()
// Try to find a window to the left of {x}
let otherWindow = undefined
for (let i = x-1; i > 0; i--) {
const w = Window.at({ x: i, y: y + 10 })
if (w !== undefined && w.app().name() !== 'Finder') {
otherWindow = w
break
}
}
if (otherWindow === undefined) {
return
}
otherWindow.focus()
})
// Focus bottom window
Key.on('j', ['option'], () => {
const window = currentWindow()
const {height: screenHeight} = Screen.main().visibleFrame()
const {x, y} = window.topLeft()
const {height: windowHeight} = window.size()
const bottom = y + windowHeight
Phoenix.log(`bottom: ${bottom}, height: ${screenHeight}, x=${x}, y=${y}`)
// Try to find a window below {bottom}
let otherWindow = undefined
for (let i = bottom; i < screenHeight; i++) {
const w = Window.at({ x: x + 10, y: y + i })
if (w !== undefined && w.app().name() !== 'Finder') {
otherWindow = w
break
}
}
if (otherWindow === undefined) {
return
}
otherWindow.focus()
})
// Focus top window
Key.on('k', ['option'], () => {
const window = currentWindow()
const {width: screenWidth} = Screen.main().visibleFrame()
const {x, y} = window.topLeft()
const {width: windowWidth} = window.size()
// Try to find a window to the top of {y}
let otherWindow = undefined
for (let i = y-1; i > 0; i--) {
const w = Window.at({ x: x + 10, y: i })
if (w !== undefined && w.app().name() !== 'Finder') {
otherWindow = w
break
}
}
if (otherWindow === undefined) {
return
}
otherWindow.focus()
})
const createTerminal = () =>
osascript(`
if application "iTerm" is running then
tell application "iTerm"
create window with default profile
end tell
else
activate application "iTerm"
end if
`)
function moveWindowToWorkspace(window, workspaceIdx) {
const targetSpace = Space.all()[workspaceIdx]
const currentSpace = Space.active()
if (currentSpace.isEqual(targetSpace)) {
return
}
targetSpace.addWindows([window])
currentSpace.removeWindows([window])
}
const NUM_SPACES = 8
for (let i = 1; i <= NUM_SPACES; i++) {
// Go to workspace $i is implemented in System Prefs/Keyboard/Mission Control
// Move current window to workspace $i
Key.on(i.toString(), ['option', 'shift'], () => {
// Move window
const window = currentWindow()
moveWindowToWorkspace(window, i-1)
// Focus first window in space
const spaceWindows = getRealWindows(Space.active())
if (spaceWindows.length == 0) {
return
}
spaceWindows[0].focus()
})
}
function windowsInSpace(space) {
const windows = space.windows()
return filterRealWindows(windows)
}
function osascript(script) {
Task.run('/usr/bin/osascript', ['-e', script])
}
Key.on('q', ['option', 'shift'], () => {
Window.focused().close()
const spaceWindows = getRealWindows(Space.active())
if (spaceWindows.length == 0) {
return
}
spaceWindows[0].focus()
})
//Key.on('g', ['option', 'shift'], () => {
// const window = currentWindow()
// const currSpace = Space.active()
// const spaces = Space.all()
// Phoenix.log(currSpace.next().hash())
// Phoenix.log(currSpace.next().next().hash())
// Phoenix.log(currSpace.next().next().next().hash())
// Phoenix.log(currSpace.next().next().next().next().hash())
// Phoenix.log( Screen.main().spaces().length)
//
// createSpace2()
//
//})
Key.on('f', ['option'], () => {
const {width, height} = Screen.main().visibleFrame()
const window = currentWindow()
window.setTopLeft({ x: 0, y: 0 })
window.setSize({ width, height })
})
// Switch layout
// 2 windows
// | A | B |
// | | |
// 3 windows
// | A | B |
// | | C |
//
// 4 windows
// | A | B |
// | D | C |
//
class X {
constructor(lol) {
this.lol = lol
}
}
class Layout {
constructor(windows) {
windows.sort((a, b) => a.hash() - b.hash())
this.windows = windows
this.focusCounter = 0
}
serialize() {
const className = this.__proto__.constructor.name
const windowHashes = this.windows.map(_ => _.hash())
const windowHashesStr = windowHashes.join(',')
return `${className}:${windowHashesStr}`
}
rotate() {
const lastWindow = this.windows.pop()
const l = this.windows.unshift(lastWindow)
Phoenix.log(lastWindow.hash(), l, this.windows.map(_ => _.hash()))
this.arrange()
}
moveToLeft(window) {
const {y} = window.topLeft()
window.setTopLeft({ x: 0, y })
}
moveToRight(window) {
const {y} = window.topLeft()
const {width} = this.screenSize()
window.setTopLeft({ x: width / 2, y })
}
moveToBottom(window) {
const {x} = window.topLeft()
const {height} = this.screenSize()
window.setTopLeft({ x, y: height / 2 })
}
moveToTop(window) {
const {x} = window.topLeft()
window.setTopLeft({ x, y: 0 })
}
maximize(window) {
const {height: screenHeight, width: screenWidth} = this.screenSize()
const {width} = window.size()
window.setSize({ width: screenWidth, height: screenHeight })
}
halveHorizontally(window) {
const {height: screenHeight} = this.screenSize()
const {width} = window.size()
window.setSize({ width, height: screenHeight / 2 })
}
halveVertically(window) {
const {width: screenWidth} = this.screenSize()
const {height} = window.size()
window.setSize({ width: screenWidth / 2, height })
}
screenSize() {
return Screen.main().visibleFrame()
}
focusNext() {
this.focusCounter = (this.focusCounter + 1) % this.windows.length
this.windows[this.focusCounter].focus()
}
static deserialize(input) {
const [className, windowHashesStr] = input.split(':')
const classRef = GLOBAL[className]
const windowHashes = new Set(windowHashesStr.split(',').map(_ => Number(_)))
let windows = []
let allWindows = Window.all()
for (const window of allWindows) {
if (windowHashes.has(window.hash())) {
windows.push(window)
}
}
const obj = new classRef(windows)
return obj
}
}
class MaximizedLayout extends Layout {
constructor(windows) {
super(windows)
}
arrange() {
Phoenix.log(`arranging MaximizedLayout ${this.windows.map(_ => _.app().name())}`)
const {width, height} = this.screenSize()
Phoenix.log(`arranging MaximizedLayout ${this.windows.map(_ => _.app().name())} with width ${width}`)
for (const window of this.windows) {
window.setTopLeft({
x: 0, y: 0,
})
window.setSize({
width: width,
height: height,
})
}
}
}
class TwoWindowLayout extends Layout {
constructor(windows) {
super(windows)
}
arrange() {
moveWindowToLeft(this.windows[0])
moveWindowToRight(this.windows[1])
}
}
class ThreeWindowLayout extends Layout {
constructor(windows) {
super(windows)
}
arrange() {
// | 0 | 1 |
// | | 2 |
moveWindowToLeft(this.windows[0])
moveWindowToRight(this.windows[1])
moveWindowToRight(this.windows[2])
const {width, height} = Screen.main().visibleFrame()
this.windows[1].setSize({
height: height / 2,
width: width / 2,
})
this.windows[1].setTopLeft({
x: width / 2,
y: 0,
})
this.windows[2].setSize({
height: height / 2,
width: width / 2,
})
this.windows[2].setTopLeft({
x: width / 2,
y: 25 + (height / 2),
})
}
}
class FourWindowLayout extends Layout {
constructor(windows) {
super(windows)
}
arrange() {
// | 0 | 1 |
// | 3 | 2 |
moveWindowToLeft(this.windows[0])
moveWindowToLeft(this.windows[3])
moveWindowToRight(this.windows[1])
moveWindowToRight(this.windows[2])
const {width, height} = this.screenSize()
// Halve windows
this.windows[0].setSize({
height: height / 2,
width: width / 2,
})
this.windows[1].setSize({
height: height / 2,
width: width / 2,
})
this.windows[2].setSize({
height: height / 2,
width: width / 2,
})
this.windows[3].setSize({
height: height / 2,
width: width / 2,
})
// Set positions for bottom windows
this.windows[3].setTopLeft({
x: 0,
y: 25 + (height / 2),
})
this.windows[2].setTopLeft({
x: width / 2,
y: 25 + (height / 2),
})
}
}
const GLOBAL = {
'FourWindowLayout': FourWindowLayout,
'ThreeWindowLayout': ThreeWindowLayout,
'TwoWindowLayout': TwoWindowLayout,
'OneWindowLayout': MaximizedLayout,
}
const MEMORY = { layout: undefined }
function getRealWindows(screenOrSpace) {
const allWindows = screenOrSpace.windows()
return filterRealWindows(allWindows)
}
const IGNORED_APPS = new Set(['Finder', 'Notification Center'])
function filterRealWindows(allWindows) {
const realWindows = []
for (const window of allWindows) {
if (!IGNORED_APPS.has(window.app().name())) {
realWindows.push(window)
}
}
return realWindows
}
// Switch layout
//
function getLayoutForScreen(screen) {
const windows = getRealWindows(screen)
const classRef = LAYOUT_MAP[windows.length] || MaximizedLayout
return new classRef(windows)
}
Key.on('i', ['shift', 'option'], () => {
const windows = getRealWindows(Space.active())
Phoenix.notify(windows.map(_ => _.app().name()).join(' | '))
})
function arrayEqual(arr1, arr2) {
if (arr1 === arr2) {
return true
}
if (arr1.length !== arr2.length) {
return false
}
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false
}
}
return true
}
function setEqual(set1, set2) {
if (set1.size !== set2.size) {
return false
}
for (const item of set1) {
if (!set2.has(item)) {
return false
}
}
return true
}
function getLayout(screen) {
const key = `screen/${screen.hash()}:layout`
let windows
if (MEMORY[key] === undefined) {
Phoenix.log('Layout not found, updating...')
MEMORY[key] = getLayoutForScreen(screen)
windows = MEMORY[key].windows
} else {
windows = getRealWindows(screen)
const windowSet = new Set(windows.map(_ => _.hash()))
const layoutWindowSet = new Set(MEMORY[key].windows.map(_ => _.hash()))
Phoenix.log(`windowSet=${Array.from(windowSet)}, layoutWindowSet=${Array.from(layoutWindowSet)}`)
if (setEqual(windowSet, layoutWindowSet)) {
Phoenix.log('Layout found AND up-to-date')
} else {
Phoenix.log('Layout found but outdated, updating...')
MEMORY[key] = getLayoutForScreen(screen)
}
}
return MEMORY[key]
}
// Switch layout
Key.on('s', ['option'], () => {
const screen = Screen.main()
const layout = getLayout(screen)
Phoenix.log(`Switching to layout ${layout.__proto__.constructor.name}`)
layout.arrange()
})
// Rotate windows
Key.on('r', ['option'], () => {
const screen = Screen.main()
const layout = getLayout(screen)
layout.rotate()
})
// Focus next
Key.on('n', ['option'], () => {
const screen = Screen.main()
const layout = getLayout(screen)
layout.focusNext()
})
const LAYOUT_MAP = {
1: MaximizedLayout,
2: TwoWindowLayout,
3: ThreeWindowLayout,
4: FourWindowLayout
}
function moveWindowToRight(window) {
const {width, height} = Screen.main().visibleFrame()
window.setTopLeft({
x: width / 2,
y: 0,
})
window.setSize({ width: width / 2, height })
}
function moveWindowToLeft(window) {
const {width, height} = Screen.main().visibleFrame()
window.setTopLeft({ x: 0, y : 0 })
window.setSize({ width: width / 2, height })
}
Key.on('e', ['option'], () => {
const {width, height} = Screen.main().visibleFrame()
const window = currentWindow()
const key = `window:${window.hash()}`
const val = Storage.get(key)
if (val === undefined || val === 'right') {
window.setTopLeft({
x: width / 2,
y: 0,
})
Storage.set(key, 'left')
} else {
window.setTopLeft({ x: 0, y : 0 })
Storage.set(key, 'right')
}
window.setSize({ width: width / 2, height })
})
// can also edit Library/Preferences/com.apple.spaces.plist and killall Finder
//https://stackoverflow.com/questions/9606221/how-can-i-programmatically-add-a-space-to-mission-control?rq=1
function createSpace() {
osascript(`
do shell script "open -a 'Mission Control'"
delay 0.5
tell application "System Events" to ¬
click (every button whose value of ¬
attribute "AXDescription" is "add desktop") of ¬
group 2 of group 1 of group 1 of process "Dock"
delay 0.5
tell application "System Events" to key code 53
`)
}
function createSpace2() {
osascript(`
do shell script "open -b 'com.apple.exposelauncher'"
delay 0.5
tell application id "com.apple.systemevents"
tell (every application process ¬
whose bundle identifier = "com.apple.dock") to ¬
click (button 1 of group 2 of group 1 of group 1)
delay 0.5
key code 53 -- esc key
end tell
`)
}
function currentWindow() {
const currentWindow = Window.focused()
if (currentWindow !== undefined) {
return currentWindow
}
return App.focused().mainWindow()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment