├── LICENSE.txt ├── README.md ├── bin ├── dired ├── ediff ├── ediff-merge ├── emacsc ├── evil └── magit └── lisp └── emacsc.el /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2024 Akinori MUSHA 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emacs as a command line tool 2 | 3 | ## emacsc(1) 4 | 5 | Emacsc(1) is a wrapper of emacsclient(1) for use within a terminal, 6 | which helps use Emacs more as command line tool than just a standalone 7 | environment. 8 | 9 | usage: emacsc [-cdgkn] [-s NAME] [-e EXPR | -x EXPR | -f FUNC] [-C DIR] [FILE..] 10 | 11 | -h, --help show this help 12 | -d, --daemon run Emacs as daemon and quit 13 | -k, --kill kill Emacs daemon 14 | -g, --no-tty do not prefer tty 15 | -c, --create-frame 16 | create a new frame 17 | -n, --no-wait 18 | do not wait and return immediately 19 | -s, --socket-name=NAME 20 | specify the file name of the socket file name for 21 | communication 22 | -e, --eval=EXPR 23 | evaluate the Lisp expression EXPR and print the 24 | result without a frame opened 25 | -x, --execute=EXPR 26 | interactively execute the Lisp expression EXPR 27 | -f, --funcall=FUNC 28 | interactively call the Lisp function FUNC 29 | -C, --chdir, --directory=DIR 30 | change to directory DIR before running code 31 | 32 | This command is a wrapper of emacsclient for use within a terminal. 33 | It adds the -t option so that Emacs opens a new frame on the current 34 | terminal, making the command itself suitable as a value for EDITOR. 35 | 36 | A byte-compiled initialization file is automatically removed before 37 | running Emacs if outdated, i.e. older than the original file. 38 | 39 | In order for the -x and -f options, and the following commands to 40 | work, install lisp/emacsc.el into a directory in your load-path and 41 | add this to your ~/.emacs.d/init.el: 42 | 43 | (require 'emacsc) 44 | 45 | Or install emacsc from an ELPA package and you are good to go. 46 | 47 | ## dired(1) 48 | 49 | Dired(1) is a frontend command to invoke dired. 50 | 51 | usage: dired [-n] [directory|file] 52 | 53 | -n, --no-wait do not wait and return immediately 54 | 55 | It takes a directory or a file name, defaulted to the current 56 | directory, to open with dired. If a non-directory is given, the point 57 | will be automatically moved to the file on startup. 58 | 59 | ## ediff(1), ediff-merge(1) 60 | 61 | Ediff(1) and ediff-merge(1) are frontend commands to invoke ediff 62 | functions. 63 | 64 | usage: ediff file1 file2 65 | 66 | usage: ediff-merge local remote base merged 67 | ediff-merge local remote merged 68 | 69 | To use them from Git, put the following lines in your 70 | ~/.config/git/config (or ~/.gitconfig). 71 | 72 | [diff] 73 | tool = ediff 74 | [difftool "ediff"] 75 | cmd = ediff \"$LOCAL\" \"$REMOTE\" 76 | [merge] 77 | tool = ediff 78 | [mergetool "ediff"] 79 | cmd = ediff-merge \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\" 80 | trustExitCode = true 81 | 82 | ## evil(1) 83 | 84 | Evil(1) is a command to edit given files in evil-local-mode. 85 | 86 | usage: evil [-s NAME] FILE.. 87 | 88 | -h, --help show this help 89 | -s, --socket-name=NAME 90 | specify the file name of the socket file name for 91 | communication 92 | 93 | ## magit(1) 94 | 95 | Magit(1) is a frontend command to invoke magit-status. 96 | 97 | usage: magit [directory] 98 | 99 | It runs magit-status on a given directory. If omitted, ask where with 100 | the current directory as default. 101 | 102 | ## SEE ALSO 103 | 104 | - [e(1) - a smart wrapper for $EDITOR](https://github.com/knu/e) 105 | 106 | ## AUTHOR 107 | 108 | Copyright (c) 2012-2024 Akinori MUSHA. 109 | 110 | Licensed under the 2-clause BSD license. See `LICENSE.txt` for 111 | details. 112 | 113 | Visit [GitHub Repository](https://github.com/knu/emacsc) for the latest 114 | information. 115 | -------------------------------------------------------------------------------- /bin/dired: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # dired(1) - a frontend command for dired 4 | # 5 | # Copyright (c) 2013-2024 Akinori MUSHA 6 | # 7 | # All rights reserved. 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in the 16 | # documentation and/or other materials provided with the distribution. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # See https://github.com/knu/emacsc for the latest information. 31 | 32 | use Cwd qw(getcwd); 33 | use File::Basename; 34 | use Getopt::Long; 35 | 36 | main(); 37 | 38 | sub usage { 39 | my $name = basename($0); 40 | 41 | print STDERR < sub { usage; exit }, 59 | "n|no-wait" => sub { push(@options, "-n") }, 60 | ) or exit 64; 61 | 62 | eval { 63 | my $cwd = getcwd(); 64 | my @files = @ARGV ? @ARGV : ($cwd); 65 | my $qcwd = elisp_string($cwd); 66 | my $qfiles = join(" ", map elisp_string($_), @files); 67 | my $elisp = "(dired-start (mapcar (lambda (f) (expand-file-name f $qcwd)) '($qfiles)))"; 68 | exec qw(emacsc -x), $elisp, @options; 69 | }; 70 | if ($@) { 71 | print STDERR basename($0), ": ", $@; 72 | exit 1; 73 | } 74 | } 75 | 76 | sub elisp_string { 77 | (local $_) = @_; 78 | s/[\\"]/\\$1/; 79 | qq{"$_"}; 80 | } 81 | -------------------------------------------------------------------------------- /bin/ediff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # ediff(1) - a frontend command for ediff 4 | # 5 | # Copyright (c) 2012, 2023 Akinori MUSHA 6 | # 7 | # All rights reserved. 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in the 16 | # documentation and/or other materials provided with the distribution. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # See https://github.com/knu/emacsc for the latest information. 31 | 32 | use Cwd qw(abs_path); 33 | use File::Basename; 34 | 35 | main(); 36 | 37 | sub main { 38 | my $name = basename($0); 39 | 40 | if (@ARGV == 7) { 41 | @ARGV = @ARGV[1, 4]; 42 | } 43 | 44 | if (@ARGV != 2) { 45 | print STDERR <&2 36 | emacsc version $VERSION 37 | 38 | usage: $(basename "$0") [-cdgkn] [-s NAME] [-e EXPR | -x EXPR | -f FUNC] [-C DIR] [FILE..] 39 | 40 | -h, --help show this help 41 | -d, --daemon run Emacs as daemon and quit 42 | -k, --kill kill Emacs daemon 43 | -g, --no-tty do not prefer tty 44 | -c, --create-frame 45 | create a new frame 46 | -n, --no-wait 47 | do not wait and return immediately 48 | -s, --socket-name=NAME 49 | specify the file name of the socket file name for 50 | communication (default: \${EMACS_SERVER_NAME:-server}) 51 | -e, --eval=EXPR 52 | evaluate the Lisp expression EXPR and print the 53 | result without a frame opened 54 | -x, --execute=EXPR 55 | interactively execute the Lisp expression EXPR 56 | -f, --funcall=FUNC 57 | interactively call the Lisp function FUNC 58 | -C, --chdir, --directory=DIR 59 | change to directory DIR before running code 60 | --version 61 | show version number and exit 62 | 63 | Default options can be put in the environment variable EMACSCOPT. 64 | 65 | This command is a wrapper of emacsclient(1) for use within a terminal. 66 | It adds the -t option so that Emacs opens a new frame on the current 67 | terminal, making the command itself suitable as a value for EDITOR. 68 | 69 | A byte-compiled initialization file is automatically removed before 70 | running Emacs if outdated, i.e. older than the original file. 71 | 72 | In order for -x and -f to work, emacsc.el must be loaded in your Emacs 73 | initialization file. 74 | 75 | (require 'emacsc) 76 | EOF 77 | } 78 | 79 | : ${ALTERNATE_EDITOR=} 80 | export ALTERNATE_EDITOR 81 | 82 | unset expr func create_frame quiet interactive void args ec_args dir 83 | tty=t 84 | dir=. 85 | 86 | if [ -n "${EMACS_SERVER_NAME:+t}" ]; then 87 | set -- -s "$EMACS_SERVER_NAME" "$@" 88 | fi 89 | 90 | if [ -n "${EMACSCOPT+t}" ]; then 91 | set -- $EMACSCOPT "$@" 92 | fi 93 | 94 | while getopts cdgkns:e:x:f:C:h-: opt; do 95 | if [ "$opt" = - ]; then 96 | case "$OPTARG" in 97 | *\=*) 98 | opt="${OPTARG%%=*}" 99 | OPTARG="${OPTARG#*=}" 100 | ;; 101 | *) 102 | opt="$OPTARG" 103 | unset OPTARG 104 | ;; 105 | esac 106 | fi 107 | 108 | case "$opt" in 109 | d|daemon) 110 | quiet=t 111 | expr="t" 112 | ;; 113 | k|kill) 114 | expr="(kill-emacs)" 115 | quiet=t 116 | ALTERNATE_EDITOR=false 117 | ;; 118 | e|eval) 119 | expr="$OPTARG" 120 | unset tty 121 | ;; 122 | x|execute) 123 | expr="$OPTARG" 124 | interactive=t 125 | void=t 126 | ;; 127 | f|funcall) 128 | func="$OPTARG" 129 | interactive=t 130 | void=t 131 | ;; 132 | C|chdir|directory) 133 | dir="$OPTARG" 134 | ;; 135 | c|create-frame) 136 | create_frame=t 137 | ;; 138 | g|no-tty) 139 | unset tty 140 | ;; 141 | n|no-wait) 142 | args="$args -n" 143 | ;; 144 | s|socket-name) 145 | ec_args="$ec_args -s $OPTARG" 146 | ;; 147 | h|help) 148 | usage 149 | exit 150 | ;; 151 | version) 152 | echo "emacsc version $VERSION" 153 | exit 154 | ;; 155 | ??*) 156 | echo "$0: illegal long option -- $opt" >&2 157 | usage 158 | exit 64 159 | ;; 160 | *) 161 | usage 162 | exit 64 163 | ;; 164 | esac 165 | done 166 | 167 | shift $((OPTIND-1)) 168 | 169 | if [ $# -gt 0 ]; then 170 | interactive=t 171 | fi 172 | 173 | for el in "$HOME"/.emacs.d/init.el "$HOME"/.emacs.el "$HOME"/.emacs; do 174 | if [ -f "$el" ]; then 175 | [ "$el" -nt "${el%.el}.elc" ] && rm -f "${el%.el}.elc" 176 | break 177 | fi 178 | done 179 | 180 | if [ -n "${func+t}" ]; then 181 | # Calling a function via call-interactively sometimes crashes the 182 | # session and makes minibuffer unusable, so avoid using it if 183 | # possible. 184 | expr="\ 185 | (let\ 186 | ((func (function $func)))\ 187 | (if (zerop (car (func-arity func)))\ 188 | (funcall func)\ 189 | (call-interactively func)))" 190 | fi 191 | 192 | if [ -d "$dir" ]; then 193 | dir=$(cd "$dir" && pwd) 194 | else 195 | echo "$0: not a directory: $dir" 196 | exit 1 197 | fi 198 | 199 | if [ -n "${expr+t}" ]; then 200 | qdir="$(sed 's/[\\"]/\\&/g' </dev/null 2>&1 226 | unset tty create_frame 227 | else 228 | case "$($ec -e window-system)" in 229 | w32) 230 | unset tty 231 | ;; 232 | ''|nil) 233 | if [ -n "${INSIDE_EMACS+t}" ]; then 234 | unset tty create_frame 235 | fi 236 | ;; 237 | *) 238 | if [ -n "${INSIDE_EMACS+t}" ]; then 239 | unset tty 240 | fi 241 | esac 242 | fi 243 | 244 | if [ -n "${tty+t}" ]; then 245 | set -- -t "$@" 246 | # emacsclient(1) calls ttyname() on stdout 247 | if [ ! -t 1 ]; then 248 | : ${TTY:=`tty 2>/dev/null`} 249 | : ${TTY:=/dev/tty} 250 | exec >$TTY 251 | fi 252 | elif [ -n "${create_frame+t}" ]; then 253 | set -- -c "$@" 254 | fi 255 | 256 | exec $ec "$@" 257 | -------------------------------------------------------------------------------- /bin/evil: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # evil(1) - edit given files in evil-local-mode 4 | # 5 | # Copyright (c) 2013 Akinori MUSHA 6 | # 7 | # All rights reserved. 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in the 16 | # documentation and/or other materials provided with the distribution. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # See https://github.com/knu/emacsc for the latest information. 31 | 32 | use strict; 33 | use warnings; 34 | use Cwd qw(abs_path getcwd); 35 | use File::Basename; 36 | use Getopt::Long; 37 | 38 | main(); 39 | 40 | sub usage { 41 | my $name = basename($0); 42 | 43 | print STDERR <<"EOF"; 44 | usage: $name [-s NAME] FILE.. 45 | 46 | -h, --help show this help 47 | -s, --socket-name=NAME 48 | specify the file name of the socket file name for 49 | communication 50 | 51 | Edit given files in evil-local-mode. 52 | 53 | This command depends on emacsc(1). Put the following lines in your 54 | Emacs initialization file. 55 | 56 | (require 'emacsc) 57 | EOF 58 | } 59 | 60 | sub main { 61 | my $opt_s; 62 | GetOptions("h|help" => sub { usage; exit }, 63 | "s|socket-name=s" => \$opt_s) or exit 64; 64 | 65 | if (1 < @ARGV) { 66 | usage; 67 | exit 64; 68 | } 69 | 70 | my @emacsc = qw(emacsc); 71 | 72 | if ($opt_s) { 73 | push @emacsc, '-s', $opt_s; 74 | } 75 | 76 | eval { 77 | if (@ARGV) { 78 | system @emacsc, '-e', <<'EOS'; 79 | (progn 80 | (autoload 'evil-local-mode "evil" "evil-local-mode" t) 81 | 82 | (defadvice server-visit-files 83 | (around evil-mode activate) 84 | (if (null files) 85 | ad-do-it 86 | (unwind-protect 87 | (progn 88 | (add-hook 'server-visit-hook 'evil-local-mode) 89 | ad-do-it) 90 | (remove-hook 'server-visit-hook 'evil-local-mode) 91 | (ad-remove-advice 'server-visit-files 'around 'evil-mode) 92 | (ad-activate 'server-visit-files))))) 93 | EOS 94 | system @emacsc, @ARGV; 95 | } else { 96 | print STDERR basename($0), ": no file is given"; 97 | exit 1; 98 | } 99 | }; 100 | if ($@) { 101 | print STDERR basename($0), ": ", $@; 102 | exit 1; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /bin/magit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # magit(1) - a frontend command for magit 4 | # 5 | # Copyright (c) 2013 Akinori MUSHA 6 | # 7 | # All rights reserved. 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in the 16 | # documentation and/or other materials provided with the distribution. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | # SUCH DAMAGE. 29 | # 30 | # See https://github.com/knu/emacsc for the latest information. 31 | 32 | use strict; 33 | use warnings; 34 | use Cwd qw(abs_path getcwd); 35 | use File::Basename; 36 | use Getopt::Long; 37 | 38 | main(); 39 | 40 | sub usage { 41 | my $name = basename($0); 42 | 43 | print STDERR < sub { usage; exit }) or exit 64; 59 | 60 | if (1 < @ARGV) { 61 | usage; 62 | exit 64; 63 | } 64 | 65 | eval { 66 | if (@ARGV) { 67 | my $dir = check_dir($ARGV[0]); 68 | exec qw(emacsc -x), 69 | sprintf(q{(magit-status "%s")}, 70 | elisp_escape($dir)); 71 | } else { 72 | my $dir = getcwd(); 73 | exec qw(emacsc -x), 74 | sprintf(q{(let ((current-prefix-arg '(4)) (default-directory "%s")) (call-interactively 'magit-status))}, 75 | elisp_escape($dir)); 76 | } 77 | }; 78 | if ($@) { 79 | print STDERR basename($0), ": ", $@; 80 | exit 1; 81 | } 82 | } 83 | 84 | sub check_dir { 85 | my($dir) = @_; 86 | 87 | -d $dir and return abs_path($dir); 88 | 89 | die sprintf("%s: %s\n", $dir, $! || 'Not a directory'); 90 | } 91 | 92 | sub elisp_escape { 93 | (local $_) = @_; 94 | s/[\\"]/\\$1/; 95 | $_; 96 | } 97 | -------------------------------------------------------------------------------- /lisp/emacsc.el: -------------------------------------------------------------------------------- 1 | ;;; emacsc.el --- helper for emacsc(1) 2 | ;; 3 | ;; Copyright (c) 2012-2024 Akinori MUSHA 4 | ;; 5 | ;; All rights reserved. 6 | ;; 7 | ;; Redistribution and use in source and binary forms, with or without 8 | ;; modification, are permitted provided that the following conditions 9 | ;; are met: 10 | ;; 1. Redistributions of source code must retain the above copyright 11 | ;; notice, this list of conditions and the following disclaimer. 12 | ;; 2. Redistributions in binary form must reproduce the above copyright 13 | ;; notice, this list of conditions and the following disclaimer in the 14 | ;; documentation and/or other materials provided with the distribution. 15 | ;; 16 | ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | ;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 | ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | ;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | ;; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | ;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | ;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | ;; SUCH DAMAGE. 27 | 28 | ;; Author: Akinori MUSHA 29 | ;; URL: https://github.com/knu/emacsc 30 | ;; Created: 11 Apr 2012 31 | ;; Version: 1.6.20241206 32 | ;; Keywords: tools 33 | 34 | ;;; Commentary: 35 | 36 | ;; emacsc(1) is a wrapper of emacsclient(1) for use within a terminal, 37 | ;; and emacsc.el is a tiny little tweak to the server module to help 38 | ;; emacsc(1) interact with the running Emacs. 39 | 40 | ;; This package contains some scripts in the `bin' directory, so 41 | ;; install them manually into a directory in your path. For example, 42 | ;; dired(1) opens a directory with dired, magit(1) opens a directory 43 | ;; with magit-status, ediff(1) is a diff(1) like tool to invoke 44 | ;; ediff-files, and so on. 45 | 46 | ;;; Code: 47 | 48 | (eval-when-compile 49 | (require 'cl-lib) 50 | (require 'dired) 51 | (require 'server)) 52 | 53 | ;;;###autoload 54 | (with-eval-after-load 'server 55 | (defun server-eval-and-print-Ad-emacsc-suppress-output (args) 56 | (let ((expr (car args))) 57 | (if (string-prefix-p "@" expr) 58 | (list (substring expr 1) nil) 59 | (cons expr (cdr args))))) 60 | (advice-add #'server-eval-and-print :filter-args #'server-eval-and-print-Ad-emacsc-suppress-output)) 61 | 62 | ;;;###autoload 63 | (defun dired-start (&optional file-or-files switches) 64 | "Start a `dired' buffer with FILE-OR-FILES selected. It can be a single file, directory or a list of files and directories. 65 | 66 | Optional second argument SWITCHES is passed through to `dired', which see." 67 | (interactive) 68 | (let ((files (if (stringp file-or-files) 69 | (list file-or-files) 70 | (or file-or-files (list default-directory))))) 71 | (if (= (length files) 1) 72 | (let* ((file (car files)) 73 | (file 74 | (if file 75 | (expand-file-name file) 76 | default-directory)) 77 | (dirname 78 | (if (file-directory-p file) 79 | file 80 | (file-name-directory file))) 81 | (buffer (dired dirname switches))) 82 | (with-current-buffer buffer 83 | (revert-buffer) 84 | (dired-goto-file 85 | (if (file-directory-p file) 86 | (concat (file-name-as-directory file) "..") 87 | file))) 88 | (switch-to-buffer buffer)) 89 | (let* ((files (mapcar #'expand-file-name files)) 90 | (root (file-name-directory (cl-reduce #'fill-common-string-prefix files))) 91 | (buffer (dired root switches))) 92 | (with-current-buffer buffer 93 | (revert-buffer) 94 | (dolist (file files) 95 | (let* ((rel (file-relative-name file root)) 96 | (components (file-name-split rel)) 97 | (dir root)) 98 | (dolist (component (butlast components)) 99 | (setq dir (expand-file-name component dir)) 100 | (and (file-directory-p dir) 101 | (dired-maybe-insert-subdir dir))) 102 | (and (dired-goto-file file) 103 | (save-excursion (dired-mark 1)))))) 104 | (switch-to-buffer buffer))) 105 | ;; force redisplay of hl-line-mode 106 | (and (bound-and-true-p hl-line-mode) 107 | (fboundp 'hl-line-highlight) 108 | (hl-line-highlight)))) 109 | 110 | (provide 'emacsc) 111 | 112 | ;;; emacsc.el ends here 113 | --------------------------------------------------------------------------------