Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

EmacsOpen.app (Pre-Alpha, not ready for use)

Main idea

Act as a share target for opening things in daemon mode Emacs, providing more macOS app-like behaviour:

  • ensure the Emacs daemon is running
  • ensure an Emacs frame is open
  • open the given thing in Emacs
  • raise the Emacs frame to the front

Handles files, web links, web page selection (Safari), and org-protocol:// links.

Targeting macOS Emacs formulas which run in daemon mode via brew service communicating via emacsclient, initially Emacs Plus.

Why?

  • To make opening things in Emacs and opening Emacs itself “Just Work”, without having to think about what state Emacs is currently in, and without having to always leave an Emacs frame open.
  • To be able to open more things in Emacs than is supported natively, including web links (for org-capture) and org-protocol:// links, to support easier sharing from other apps to Emacs.
  • To achieve the above in a single tool with minimal configuration.

Status: In development

  • Initial app and CLI build
  • Most of the CLI variants implemented, without daemon management.
  • Expect frequent history rewrites.
  • See roadmap below for rough plan.
  • Not ready for public use.

CLI command emacsopen structure

  • Syntax: emacsopen [OPTIONS] [FILE...]
    • OPTIONS: [--tty/-t] | [--eval/-e] | [--block/-b] [--create-frame/-c]
      • --tty/-t Use Emacs in terminal mode.
      • --eval/-e Evaluate Emacs Lisp commands.
      • --block/-b Block (wait) until Emacs has finished handling the given file or link. Default is to not wait.
      • --create-frame/-c Always create a new frame rather than the default of reusing an existing one.
      • The --tty/-t and --eval/-e options are mutually exclusive, and incompatible with --block/-b and --create-frame/-c.
    • FILE... A set of files or an org-protocol link to open in Emacs.
  • Examples:
    • To activate an Emacs frame, preferring to reuse an one:
      • emacsopen
    • To open a file or org-protocol link in the GUI:
      • emacsopen file.org
      • emacsopen org-protocol://...
    • To open a file in the terminal:
      • emacsopen --tty README.org
    • To just ensure that the Emacs daemon is ready for commands:
      • emacsopen --eval nil
  • To just ensure that emacsclient is ready: emacsopen --eval nil

Roadmap

  • [X] Address potential roadblocks to see if viable at all: try calling emacsclient from the app
  • [X] Skeleton app
    • [X] Skeleton emacsopen command
    • [X] XCode project for app, using CLI/library as internal dependency
  • [ ] Read config (see also ‘Auto detection’ below)
    • [ ] Location of emacsclient
      • Can rely on PATH for the terminal case.
    • [ ] Name of brew service to use for starting Emacs daemon
    • [ ] org-protocol:// scheme config
      • Follow the most popular convention by default.
  • [ ] Handle opening files via drag and drop and opening via Finder (with frame already open). Or maybe just as ‘Open With…’
  • [ ] Handle reactivation via tell application "EmacsOpen" to activate when open and when closed
  • [ ] Register as default handler for *.org files
  • [-] Handle org-protocol:// links (with frame already open)
    • [ ] To open an existing Org node by its Org ID
    • [ ] To capture a web page, with url, title, and optional selected text
    • [X] To trigger org-capture, eg to add an inbox item
  • [ ] Consider adding an additional URL handler too. Options
    • org-id://foo&create-frame=n
    • org://open?id=foo&create-frame=n
    • emacs://open?id=foo
    • emacsopen://quit
  • [X] Always activate Emacs top window
  • [X] Open frame if necessary
  • [ ] Start daemon if necessary, waiting until ready for emacsclient commands
  • [X] open -a EmacsOpen should open Emacs, creating a frame if necessary, and activate Emacs
  • [X] open -a EmacsOpen foo.txt should open Emacs, creating a frame if necessary, and activate Emacs, with the given (existing) file
  • [ ] Ensure useful for emacs restart
    • Eg support brew services stop emacs-plus@30; doom sync; emacsopen activate-frame
  • [ ] Act as a share target to invoke the command org-protocol convention of url, title, and text.
  • [ ] Act as a Safari extension with support for sharing current page (including text selection) via org-protocol, including keyboard shortcut support
  • [X] Add eval support (using emacsclient -e)
  • [ ] Add a Homebrew formula, including shell completions
  • [X] Support in-terminal case: emacsclient --tty
  • [X] Shell autocompletion of CLI arguments using apple/swift-argument-parser
  • [ ] Docs (expand this README)
  • [ ] Tests
  • [ ] CI (build, test, dependabot checks)
  • [ ] Show visual feedback when getting Emacs ready (eg a HUD spinner) when taking too long (GUI case only)
  • [ ] Companion project on iOS to route org-protocol:// links to chosen iOS apps with their own URL schemes, such as beorg://

Potential scope

Auto detection instead of relying on config

  • Auto-detect Emacs brew service name if not configured, eg using brew services list --json
  • Auto-detect emacsclient path if not configured if at /opt/homebrew/bin/emacsclient

Limited Shortcuts.app support

Currently Shortcuts.app can’t use emacsclient in Emacs Plus due to socket/env related issues. Support some way of opening a file or link via EmacsOpen either via CLI or a Siri Shortcut action.

Out of scope

  • No GUI
    • All user interactions should be via a share action, or the emacsopen CLI command.
    • All configuration should be a text file, probably TOML format.
    • All responses should be via stdout (CLI), macOS error notification/alert, and maybe logging.
  • No AppleScript support
    • Use Emacs lisp instead: emacsopen -e COMMAND

Background

This started as a discussion on an Emacs Plus PR thread.

About

Share files and links to daemon mode Emacs on macOS easily 🦄

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages