7

有很多关于从命令行访问 Sublime Text 2 编辑器的问题。总之,响应是创建符号链接、别名或简单的 shell 脚本来运行适当的 sublime_text 命令。我能做到。我想要的是让 linux 版本表现得像 MacOS 版本。

在 MacOS 上,我有以下内容:

ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl ~/bin/subl

然后在我的 .zshrc 中:

alias subl="$HOME/bin/subl -n"
export EDITOR="$HOME/bin/subl -n -w"

这有两件事。它给了我一个subl命令,可以在新窗口中打开命令行中给出的任何文件。该subl命令不会阻止终端。它还设置了我的编辑器以打开崇高的文本来编辑参数,但这次它确实阻塞了。特别是,$EDITOR阻塞直到它的参数被关闭。它不会阻塞无关的崇高文本窗口。

我可以通过以下方式在 linux 上实现类似的效果:

在 ~/bin/subl 中:

#! /bin/zsh

$HOME/Sublime\ Text\ 2/sublime_text -n $@ &

然后在 ~/bin/subl_wait: (想想mate_waitTextMate 用户)

#! /bin/zsh

exec $HOME/Sublime\ Text\ 2/sublime_text -n -w $@

然后我可以设置EDITORsubl_wait,并且几乎可以正常工作。 subl打开文件进行编辑并且不阻止。 subl_wait打开文件进行编辑并阻止。

问题是subl_wait等到所有打开的文件都关闭,而不仅仅是它的参数。

有没有可能让这个工作完美?

4

3 回答 3

8

看来我已经找到问题了。(感谢这篇文章:http ://www.sublimetext.com/forum/viewtopic.php?f=2&t=7003 )

基本点:sublime 的行为会根据实例是否已经在运行而有所不同!

如果一个实例已经在运行,那么 Linux 上的 sublime 的行为类似于 MacOS。如果没有实例正在运行,则终端会阻塞,直到您退出 sublime。

考虑到这一点,我们只需要修改脚本以确保 sublime 正在运行:

~/bin/subl_start

#! /bin/zsh

if [ ! "$(pidof sublime_text)" ] ; then
  # start sublime text main instance
  # echo "Starting Sublime Text 2"
  $HOME/Sublime\ Text\ 2/sublime_text &
  sleep 1 # needed to avoid a race condition
fi

~/bin/subl

#! /bin/zsh

. $HOME/bin/subl_start

exec $HOME/Sublime\ Text\ 2/sublime_text -n $@

~/bin/subl_wait

#! /bin/zsh

. $HOME/bin/subl_start

exec $HOME/Sublime\ Text\ 2/sublime_text -n -w $@

请注意,我在-n任何地方都使用了这些标志。这可能不是你的一杯茶。如果您正在使用,-n那么您可能还想查看您的close_windows_when_empty设置。

于 2013-01-31T22:17:25.450 回答
5

受 OP 回答的启发,我bash 为 Sublime Text 创建了一个包装脚本,其中包含您的所有发现并在 OSX 和 Linux 上运行

它的目的有三个:

  • 提供一个统一的sublCLI,其工作方式类似于 STsubl在 OSX 上自己的工作方式:调用 ST而不阻塞,除非显式请求等待
  • 为 Linux 上与等待相关的错误封装了一个解决方法。
  • 当保存或符号链接到 as 时sublwait,提供一个自动应用and选项的sublwaitCLI ,以使其适合使用(请注意,某些程序,例如,要求仅包含可执行文件的名称 - 不支持可执行文件 + 选项); 还确保至少指定了一个文件。--wait--new-window$EDITORnpm$EDITOR

唯一悬而未决的问题是 OP 避免竞争条件的方法是否sleep 1足够强大。

更新:请注意,subl在 OSX 上默认情况下不放置在$PATH- 您通常必须手动执行此操作。如果您还没有这样做,脚本现在将subl位于 ST 的应用程序包中;(它按以下顺序尝试应用程序名称:'Sublime Text'、'Sublime Text 2'、'Sublime Text 3',首先在 中/Applications,然后在 中~/Applications。)

这是运行脚本的输出-h

Multi-platform (OSX, Linux) wrapper script for invocation of Sublime Text (ST)
from the command line.

Linux:
  Works around undesired blocking of the shell (unless requested)
  and a bug when waiting for specific files to be edited.
Both platforms:
  When invoked as `sublwait`, automatically applies the
    --wait --new-window
  options to make it suitable for use with $EDITOR.

Therefore, you can to the following:
- Name this script `subl` for a CLI that supports ALL options.
  (On OSX, this will simply defer to the `subl` CLI that came with ST.)
- Place the script in a directory in your $PATH.
- In the same directory, create a symlink to the `subl` script named
  `sublwait`:
    ln -s subl sublwait
  and, if desired, add
    export EDITOR=sublwait
  to your shell profile.

请注意,如果您只使用 OSX,您可以使用 ST 自己的subl并将此脚本直接保存为sublwait.

脚本来源:

#!/usr/bin/env bash

# Multi-platform (OSX, Linux) wrapper script for invocation of Sublime Text (ST)
# from the command line. Invoke with -h for details.

[[ $1 == '-h' || $1 == '--help' ]] && showHelpOnly=1 || showHelpOnly=0
[[ $(basename "$BASH_SOURCE") == 'sublwait' ]] && invokedAsSublWait=1 || invokedAsSublWait=0
[[ $(uname) == 'Darwin' ]] && isOsX=1 || isOsX=0

# Find the platform-appropriate ST executable.
if (( isOsX )); then # OSX: ST comes with a bona-fide CLI, `subl`.

  # First, try to find the `subl` CLI in the $PATH.
  # Note: This CLI is NOT there by default; it must be created by symlinking it from
  #       its location inside the ST app bundle.
  # Find the `subl` executable, ignoring this script, if named subl' as well, or a
  # script by that name in the same folder as this one (when invoked via symlink 'sublwait').
  stExe=$(which -a subl | fgrep -v -x "$(dirname "$BASH_SOURCE")/subl" | head -1)
  # If not already in the path, look for it inside the application bundle. Try several locations and versions.
  if [[ -z $stExe ]]; then
    for p in {,$HOME}"/Applications/Sublime Text"{,' 2',' 3'}".app/Contents/SharedSupport/bin/subl"; do
      [[ -f $p ]] && { stExe=$p; break; }
    done
  fi
  [[ -x $stExe ]] || { echo "ERROR: Sublime Text CLI 'subl' not found." 1>&2; exit 1; }

else # Linux: `sublime_text` is the only executable - the app itself.

  stExe='sublime_text'
  which "$stExe" >/dev/null || { echo "ERROR: Sublime Text executable '$stExe' not found." 1>&2; exit 1; }

fi

# Show command-line help, if requested.
# Add preamble before printing ST's own help.
# Note that we needn't worry about blocking the
# shell in this case - ST just outputs synchronously
# to stdout, then exits.
if (( showHelpOnly )); then

  bugDescr=$(
    cat <<EOF
works around a bug on Linux (as of v2.0.2), where Sublime Text,
if it is not already running, mistakenly blocks until it is exited altogether.
EOF
  )

  if (( invokedAsSublWait )); then

    # We provide variant-specific help here.
    cat <<EOF

Wrapper script for Sublime Text suitable for use with the \$EDITOR variable.

Opens the specified files for editing in a new window and blocks the 
invoking program (shell) until they are closed.
In other words: the --wait and --new-window options are automatically
applied.

Aside from encapsulating this functionality without the need for options
- helpful for tools that require \$EDITOR to be an executable name only -
$bugDescr

Usage: sublwait file ...

EOF
    # Note: Adding other options doesn't make sense in this scenario
    #       (as of v2.0.2), so we do NOT show ST's own help here.

  else

    cat <<EOF

Multi-platform (OSX, Linux) wrapper script for invocation of
Sublime Text (ST) from the command line.

Linux:
  Works around undesired blocking of the shell (unless requested)
  and a bug when waiting for specific files to be edited.
Both platforms:
  When invoked as \`sublwait\`, automatically applies the
    --wait --new-window
  options to make it suitable for use with \$EDITOR.

Therefore, you can to the following:
- Name this script \`subl\` for a CLI that supports ALL options.
  (On OSX, this will simply defer to the \`subl\` CLI that came with ST.)
- Place the script in a directory in your \$PATH.
- In the same directory, create a symlink to the \`subl\` script named
  \`sublwait\`:
    ln -s subl sublwait
  and, if desired, add
    export EDITOR=sublwait
  to your shell profile.

Sublime Text's own help:
------------------------
EOF

    # Finally, print ST's own help and exit.
    exec "$stExe" "$@"

  fi
  exit 0
fi


# Invoked as `sublwait`? -> automatically apply --wait --new-window options.
if (( invokedAsSublWait )); then

  # Validate parameters.
  # - We expect NO options - to keep things simple and predictable, we do NOT allow
  #   specifying additional options (beyond the implied ones).
  # - We need at least 1 file argument.
  # - As a courtesy, we ensure that no *directories* are among the arguments - ST doesn't support
  #  that properly (always waits for ST exit altogether); beyond that, however, we leave input
  #  validation to ST.
  if [[ "$1" =~ ^-[[:alnum:]]+$ || "$1" =~ ^--[[:alnum:]]+[[:alnum:]-]+$ ]]; then # options specified?
    { echo "ERROR: Unexpected option specified: '$1'. Use -h for help." 1>&2; exit 1; }
  elif (( $# == 0 )); then # no file arguments?
    { echo "ERROR: Missing file argument. Use -h for help." 1>&2; exit 1; }
  else # any directories among the arguments?
    # Note: We do NOT check for file existence - files could be created on demand.
    #       (Things can still go wrong - e.g., /nosuchdir/mynewfile - and ST doesn't
    #       handle that gracefully, but we don't want to do too much here.)
    for f in "$@"; do
      [[ ! -d "$f" ]] || { echo "ERROR: Specifying directories is not supported: '$f'. Use -h for help." 1>&2; exit 1; }
    done
  fi

  # Prepend the implied options.
  set -- '--wait' '--new-window' "$@"

fi

# Finally, invoke ST:
if (( isOsX )); then # OSX

  # `subl` on OSX handles all cases correctly; simply pass parameters through.
  exec "$stExe" "$@"

else # LINUX: `sublime_text`, the app executable itself, does have a CLI, but it blocks the shell.

  # Determine if the wait option was specified.
  mustWait=0
  if (( invokedAsSublWait )); then
    mustWait=1
  else
    # Look for the wait option in the parameters to pass through.
    for p in "$@"; do
      [[ $p != -* ]] && break # past options
      [[ $p == '--wait' || $p =~ ^-[[:alnum:]]*w[[:alnum:]]*$ ]] && { mustWait=1; break; }
    done
  fi

  if (( mustWait )); then # Invoke in wait-for-specified-files-to-close mode.

    # Quirk on Linux:
    # If sublime_text isn't running yet, we must start it explicitly first.
    # Otherwise, --wait will wait for ST *as a whole* to be closed before returning, 
    # which is undesired.
    # Thanks, http://stackoverflow.com/questions/14598261/making-sublime-text-2-command-on-linux-behave-as-it-does-on-macos-x
    if ! pidof "$stExe" 1>/dev/null; then
        # Launch as BACKGROUND task to avoid blocking.
        # (Sadly, the `--background` option - designed not to activate the Sublime Text window 
        #  on launching - doesn't actually work on Linux (as of ST v2.0.2 on Ubuntu 12.04).)
        ("$stExe" --background &)
        # !! We MUST give ST some time to start up, otherwise the 2nd invocation below will be ignored.
        # ?? Does a fixed sleep time of 1 second work reliably?
        sleep 1
    fi

    # Invoke in blocking manner, as requested.
    exec "$stExe" "$@"

  else # Ensure invocation in NON-blocking manner.

    if ! pidof "$stExe" 1>/dev/null; then # ST isn't running.
      # If ST isn't running, invoking it *always* blocks.
      # Therefore, we launch it as a background taks.
      # Invocation via a subshell (parentheses) suppresses display of the 
      # background-task 'housekeeping' info.
      ("$stExe" "$@" &)
    else # ST is already running, we can safely invoke it directly without fear of blocking.
      exec "$stExe" "$@"
    fi

  fi

fi
于 2013-12-14T19:16:31.140 回答
2

在 Ubuntu Gnu/Linux 13.04 64 位上:

我只是让 subl 几乎一直在运行。所以我的 git 配置有: core.editor=/usr/bin/subl -n -w

这就是我所需要的。我用 ctrl-s 保存 git commit 文件,用 ctrl-w 关闭窗口,我就完成了。但是我必须通过点击右上角的 X来真正关闭窗口...... 96% 完美。

于 2013-08-14T19:35:42.447 回答