在Linux上制作Sublime Text 2命令就像在MacOS X上一样

use*_*209 7 linux sublimetext2

有很多问题要求从命令行访问Sublime Text 2编辑器.总之,响应是使用符号链接,别名或简单的shell脚本来运行相应的sublime_text命令.我能做到.我想要的是使linux版本的行为类似于MacOS版本.

在MacOS上,我有以下内容:

ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl ~/bin/subl
Run Code Online (Sandbox Code Playgroud)

然后在我的.zshrc中:

alias subl="$HOME/bin/subl -n"
export EDITOR="$HOME/bin/subl -n -w"
Run Code Online (Sandbox Code Playgroud)

这样做有两件事.它给了我一个subl命令,打开在新窗口中命令行上给出的任何文件.该subl命令不会阻止终端.它还设置我的编辑器打开sublime文本来编辑参数,但这次它确实阻止了.特别是,$EDITOR其参数关闭之前阻塞.它不会阻止不相关的sublime文本窗口.

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

在〜/ bin/subl中:

#! /bin/zsh

$HOME/Sublime\ Text\ 2/sublime_text -n $@ &
Run Code Online (Sandbox Code Playgroud)

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

#! /bin/zsh

exec $HOME/Sublime\ Text\ 2/sublime_text -n -w $@
Run Code Online (Sandbox Code Playgroud)

那么我可以设置EDITORsubl_wait,事情差不多的工作. subl打开文件进行编辑,不会阻止. subl_wait打开文件进行编辑并阻止.

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

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

use*_*209 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
Run Code Online (Sandbox Code Playgroud)

~/bin/subl:

#! /bin/zsh

. $HOME/bin/subl_start

exec $HOME/Sublime\ Text\ 2/sublime_text -n $@
Run Code Online (Sandbox Code Playgroud)

~/bin/subl_wait:

#! /bin/zsh

. $HOME/bin/subl_start

exec $HOME/Sublime\ Text\ 2/sublime_text -n -w $@
Run Code Online (Sandbox Code Playgroud)

请注意,我-n到处都使用过这些标志.这可能不是你的一杯茶.如果您正在使用,-n那么您可能还想查看您的close_windows_when_empty设置.


mkl*_*nt0 5

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

它的目的有三个:

  • 提供一个统一的sublCLI,它subl在STX上就像ST一样:在不阻塞的情况下调用ST ,除非明确请求等待.
  • 封装了Linux上与等待相关的错误解决方法.
  • 当保存或符号链接为时sublwait,提供一个自动应用和选项的sublwaitCLI,以使其适合使用(请注意,某些程序,例如,要求仅包含可执行文件的名称 - 不支持可执行文件+选项); 还确保至少指定了一个文件.--wait--new-window$EDITORnpm$EDITOR

唯一尚未解决的问题是OP是否采取了避免竞争条件的方法sleep 1- 足够强大.

更新:请注意,sublOSX默认情况下不会放在$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.
Run Code Online (Sandbox Code Playgroud)

请注意,如果您只使用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
Run Code Online (Sandbox Code Playgroud)