12. Emacs vs. Vi vs. Eclipse vs. anyIDE

The pro’s and con’s in the religious editor war.

12.1. How to install latest stable Emacs in Ubuntu

Prerequisites:

apt-get install apel

For latest emacs stable releases on ubuntu (also recommended by How to Install GNU Emacs 26.1 in Ubuntu):

add-apt-repository ppa:kelleyk/emacs

apt-get update && \
apt-get install emacs26 emacs26-el && \
update-alternatives --set emacs /usr/bin/emacs26

12.1.1. Setup for emacsen-common

Integration with emacsen-common is not so hard. Here are the one-time actions:

touch /var/lib/emacsen-common/state/flavor/installed/emacs26

mkdir -p /etc/emacs26/site-start.d
mkdir -p /usr/share/emacs26/site-lisp
test -L /usr/share/emacs/26.?/site-lisp || \
mv /usr/share/emacs/26.?/site-lisp/* /usr/share/emacs26/site-lisp/

Followed by the upgrade actions, after a new emacs release was installed:

test -L /usr/share/emacs/26.?/site-lisp || \
rm -rf /usr/share/emacs/26.?/site-lisp
rm -f /usr/share/emacs/26.?/site-lisp
ln -s ../../emacs26/site-lisp  /usr/share/emacs/26.?/

If /usr/share/emacs26/site-lisp/subdirs.el has previously been updated, it is not necessary to apply the following modifications.

Since subdirs.el is loaded before site-init is inhibited, it can be used as replacement for startup.el. Create /usr/share/emacs26/site-lisp/subdirs.el:

;; |:here:|
cat <<'EOF' >/usr/share/emacs26/site-lisp/subdirs.el
(defvar package--builtin-versions
  ;; Mostly populated by loaddefs.el via autoload-builtin-package-versions.
  (purecopy `((emacs . ,(version-to-list emacs-version))))
  "Alist giving the version of each versioned builtin package.
I.e. each element of the list is of the form (NAME . VERSION) where
NAME is the package name as a symbol, and VERSION is its version
as a list.")

(defun package--description-file (dir)
  (concat (let ((subdir (file-name-nondirectory
                         (directory-file-name dir))))
            (if (string-match "\\([^.].*?\\)-\\([0-9]+\\(?:[.][0-9]+\\|\\(?:pre\\|beta\\|alpha\\)[0-9]+\\)*\\)" subdir)
                (match-string 1 subdir) subdir))
          "-pkg.el"))

(defconst debian-emacs-flavor 'emacs26
  "A symbol representing the particular debian flavor of emacs running.
Something like 'emacs20, 'xemacs20, etc.")

(if (fboundp 'normal-top-level-add-subdirs-to-load-path)
    (normal-top-level-add-subdirs-to-load-path))

(let ((local-site-lisp "/usr/local/share/emacs/26.3/site-lisp/"))
  (make-directory local-site-lisp t)
  (if (not (member local-site-lisp load-path))
      (setq load-path (cons local-site-lisp load-path))))
EOF
;; |:here:| `

Now add the debian specific startup to /usr/share/emacs26/site-lisp/site-start.el:

;; |:here:|
cat <<'EOF' >/usr/share/emacs26/site-lisp/site-start.el
(if (load "debian-startup" t t nil)
    (debian-startup debian-emacs-flavor))
EOF
;; |:here:| `

12.1.2. Obsolete packages

Remove these packages, since they do not work:

apt-get purge prolog-el
apt-get purge dash-el

12.1.3. Modify/repair packages

If necessary (Ubuntu 16.04/18.04):

grep '(("\\\\\\\\\[Ss]ubref{\\\\(\[^{}\\n\\r\\\\%,\]\*\\\\)" 1 LaTeX-label-list "}")))' /usr/share/emacs/site-lisp/auctex/style/subfigure.el

apply auctex patch manually (obviously this will not work with patch(1), since TABs are lost):

--- /usr/share/emacs/site-lisp/auctex/style/subfigure.el-000 2015-11-19 15:26:11.000000000 +0100
+++ /usr/share/emacs/site-lisp/auctex/style/subfigure.el     2019-09-03 21:03:22.354599330 +0200
@@ -47,8 +47,8 @@
    ;; Install completion for labels:
    (setq TeX-complete-list
         (append
-      '(("\\\\[Ss]ubref{\\([^{}\n\r\\%,]*\\)" 1 LaTeX-label-list "}")))
-      TeX-complete-list)
+      '(("\\\\[Ss]ubref{\\([^{}\n\r\\%,]*\\)" 1 LaTeX-label-list "}"))
+      TeX-complete-list))

    ;; Fontification
    (when (and (featurep 'font-latex)

Before installing the new emacs, repair package apel. If necessary (Ubuntu 16.04):

grep '[^\][\]N' /usr/share/emacs/site-lisp/apel/poe.el

replace \N in doc strings of /usr/share/emacs/site-lisp/apel/poe.el with \\N:

vi /usr/share/emacs/site-lisp/apel/poe.el
:
1,$s,\\N,\\\\N,g

Hint: the substitution command works also fine in sed(1).

12.1.4. Activate packages

Add emacs26 to packages depending on emacs flavor. If emacs25 is also installed from kelleyk/emacs repository, additionally remove emacs25:

/bin/grep --color -nH -e 'emacs2[45]' /usr/lib/emacsen-common/packages/*/* /usr/sbin/update-auctex-elisp

/usr/lib/emacsen-common/packages/install/auctex:116:    (emacs24|emacs26|emacs-snapshot)
/usr/lib/emacsen-common/packages/install/psgml:50:    emacs26 | emacs24)
/usr/lib/emacsen-common/packages/remove/auctex:60:    (emacs24|emacs26|emacs-snapshot)
/usr/lib/emacsen-common/packages/remove/psgml:52:    emacs21 | emacs22 | emacs23 | emacs24 | emacs26 | emacs-snapshot)
/usr/sbin/update-auctex-elisp:56:FLAVORS=${*:-'emacs24 emacs26 emacs-snapshot'}

|:todo:| do it manually a couple of times, then write a script (python(1) or sed(1))

12.1.5. Optional packages

If dvc is installed, put this at the start of /etc/emacs/site-start.d/50dvc.el to activate the ewoc system package.

;; |:here:| `
(condition-case err
    (let ((load-path (reverse load-path)))
      ;; search system libraries first
      (require 'ewoc))
  (error (message "error: %s" (error-message-string err))))
;; |:here:| `

12.1.6. Integrate emacs into emacsen-common

Now update site-lisp with the intstalled debian packages:

/usr/lib/emacsen-common/emacs-install emacs26

Note

if emacs26 was already installed before the emacsen-common integration was conducted, reconfigure emacsen-common packages:

dpkg-reconfigure $( ls -1 /usr/lib/emacsen-common/packages/install/* | sed 's,.*/,,' | sort | uniq )

12.2. Point, mark, region, kill ring

In Emacs, the point is the current position of cursor:

Some text POINTat some position
continued on next line. Lorem ipsum dolor.

The key sequence C-SPC sets the position of the mark to the position of point:

Some text MARKPOINTat some position
continued on next line. Lorem ipsum dolor.

When point is moved, the mark stays in place:

Some text MARKat some position
continuedPOINT on next line. Lorem ipsum dolor.

The region is the text between mark and point:

at some position
continued

C-x C-x exchanges point and mark. It also activates the region:

Some text POINTat some position
continuedMARK on next line. Lorem ipsum dolor.

The region can always be moved or copied onto the kill ring, which acts like a clipboard with a history of killed/copied strings. If the region is active (highlighted), pressing BACKSPC removes the region without copying it to the kill ring.

Emacs Notepad Description
C-SPC SHIFT mark beginning of region
C-w C-x move region to kill ring
M-w C-c copy region to kill ring
C-y C-v insert last string from kill ring
M-y
directly after C-y or M-y replaces inserted string with previous string from kill ring
C-u - M-y
directly after C-y or M-y replaces inserted string with next string from kill ring

Emacs allows to handle line ends without explicitely setting the mark:

Emacs Notepad Description
C-k S-end C-x move line without line break to kill ring
C-k C-k S-end right C-x move line to kill ring
C-k C-k C-y S-end right C-c copy line to kill ring

Emulating the special kill-line functionality with the region is more involved:

Emacs Notepad Description
C-SPC C-e right C-w S-end C-x move line without line break to kill ring
C-SPC C-e right C-w S-end right C-x move line to kill ring
C-SPC C-e right M-w S-end right C-c copy line to kill ring
C-SPC C-e right BACKSPC S-end right <ANYTHING> delete line without affecting kill ring

Other commands for killing text entities:

Shortcut Command Description
M-d M-x kill-word kill word
C-M-k M-x kill-sexp kill S-expression
  M-x kill-sentence kill sentence
  M-x kill-paragraph kill paragraph
  M-x kill-comment kill comment

12.3. Undo

  • The Emacs undo semantics is lossless.
  • Vi has a lossless (and persistent) undo tree and so does Emacs (Emacs: Undo Tree package)

12.3.1. Standard Undo Function

The standard undo semantics of adding edits, undo some and – with the next edit – loose everything that was undone is just silly.

Step Action Description
Edit 4 chunks added a, b, c, d
Undo 2 chunks removed d, c
Edit 2 chunks added e, f
Undo 2 chunks removed f, e
  Undo 1 chunk removed b

digraph graph0 { subgraph cluster_graph0 { n0 [label="1",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a0 [label="a"]; b0 [label="b"]; c0 [label="c"]; d0 [label="d"]; edge [style=solid,dir=forward,color=green]; a0 -> b0 -> c0 -> d0; } subgraph cluster_graph1 { n1 [label="2",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a1 [label="a"]; b1 [label="b"]; c1 [label="c"]; d1 [label="d"]; edge [style=dashed,dir=none,color=green]; a1 -> b1 -> c1 -> d1; edge [style=solid,dir=forward,color=red]; d1 -> c1 -> b1; } subgraph cluster_graph2 { n2 [label="3",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a2 [label="a"]; b2 [label="b"]; c2 [label="c",style=invis]; d2 [label="d",style=invis]; e2 [label="e"]; f2 [label="f"]; edge [style=dashed,dir=none,color=green]; a2 -> b2; edge [style=invis,dir=none,color=red]; b2 -> c2 -> d2 -> c2 -> b2; edge [style=solid,dir=forward,color=green]; b2 -> e2 -> f2; } subgraph cluster_graph3 { n3 [label="4",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a3 [label="a"]; b3 [label="b"]; c3 [label="c",style=invis]; d3 [label="d",style=invis]; e3 [label="e"]; f3 [label="f"]; edge [style=dashed,dir=none,color=green]; a3 -> b3; edge [style=invis,dir=none,color=red]; b3 -> c3 -> d3 -> c3 -> b3; edge [style=dashed,dir=none,color=green]; b3 -> e3 -> f3; edge [style=solid,dir=forward,color=red]; f3 -> e3 -> b3 -> a3; } }

12.3.2. Emacs Undo Function

For Emacs an undo that removes a previous edit is just another action that can be undone later.

Step Action Description
Edit 4 chunks added a, b, c, d
Undo 2 chunks removed d, c
Edit 2 chunks added e, f
Undo 2 chunks removed f, e
  Undo 2 chunks added c, d

digraph graph0 { subgraph cluster_graph0 { n0 [label="1",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a0 [label="a"]; b0 [label="b"]; c0 [label="c"]; d0 [label="d"]; // edge [style=invis]; // n0 -> a0; edge [style=solid,dir=forward,color=green]; a0 -> b0 -> c0 -> d0; } subgraph cluster_graph1 { n1 [label="2",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a1 [label="a"]; b1 [label="b"]; c1 [label="c"]; d1 [label="d"]; edge [style=dashed,dir=none,color=green]; a1 -> b1 -> c1 -> d1; edge [style=solid,dir=forward,color=red]; d1 -> c1 -> b1; } subgraph cluster_graph2 { n2 [label="3",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a2 [label="a"]; b2 [label="b"]; c2 [label="c"]; d2 [label="d"]; e2 [label="e"]; f2 [label="f"]; edge [style=dashed,dir=none,color=green]; a2 -> b2 -> c2 -> d2; edge [style=dashed,dir=none,color=red]; d2 -> c2 -> b2; edge [style=solid,dir=forward,color=green]; b2 -> e2 -> f2; } subgraph cluster_graph3 { n3 [label="4",shape=circle;fontsize=10,widht=0.4,height=0.4;fixedsize=true]; a3 [label="a"]; b3 [label="b"]; c3 [label="c"]; d3 [label="d"]; e3 [label="e"]; f3 [label="f"]; edge [style=dashed,dir=none,color=green]; a3 -> b3 -> c3 -> d3; edge [style=dashed,dir=none,color=red]; d3 -> c3 -> b3; edge [style=dashed,dir=none,color=green]; b3 -> e3 -> f3; edge [style=solid,dir=forward,color=red]; f3 -> e3 -> b3; edge [style=solid,dir=forward,color=green]; b3 -> c3 -> d3; } }

12.3.3. Emacs Undo Tree

The Emacs: Undo Tree package realizes the previously described tree structure removing the recursion from branches. It offers a visual interface (C-x u) for easy navigation and fancy display of diffs .

C-/ undo-tree-undo
C-_ undo-tree-undo
C-? undo-tree-redo
C-x u undo-tree-visualize

12.4. Abbreviations

vi(1) supports abbreviations and mappings with :abbrev (:iabbrev) and :map.

In order to define an abbreviation local to major mode with replacement of @here@ tag in Emacs, type:

C-SPC (if SPC @here@ SPC run-a-command) C-x a x l xxif RETURN

Both, automatic expansion in abbrev mode:

xxif SPC

and explicit expansion with inactive abbrev mode:

xxif C-x a e

expand to:

(if POINT run-a-command)
Shortcut Command Description
C-x a x m M-x abbrevx-toggle-abbrev-mode private command to toggle abbrev mode globally
C-x a x g M-x abbrevx-add-global-abbrev private command to define global abbreviation from current region, replacing @here@ tag on expansion
C-x a x l M-x abbrevx-add-mode-abbrev private command to define mode specific abbreviation from current region, replacing @here@ tag on expansion
C-x a e M-x expand-abbrev expand abbreviation before point
C-x a g M-x add-global-abbrev define global abbreviation, which works in all major modes
C-x a l M-x add-mode-abbrev define mode specific abbreviation, which only works in current major mode

12.5. Dynamic Abbreviation Expansion

vim(1) supports dynamic abbreviations in insert mode with C-P and C-N. vi(1) does not support this extension.

M-/ = Alt+Shift+7

Start typing a word, e.g. dy, then press M-/ repeatedly. All open buffers (not just project files) are searched for a matching expansion:

dynamic
dylan
dyl
dylan-console
dylan-repl
dylanlid
dylan-lid
dy

This is extremely useful for using long identifiers in programs:

VERY_LONG_IDENTIFIERS_WHICH_NOBODY_WANTS_TO_TYPE = "value"

...

VE RY_LONG_IDENTIFIERS_WHICH_NOBODY_WANTS_TO_TYPE

Eclipse only has a very limited functionality for mainly strongly typed, object oriented languages:

object. <popup>

12.6. Key Sequences

Vi supports key sequences as mappings (:map, :imap).

It seems possible to define key sequences in Eclipse: Eclipse - Bindings.

12.7. Extensions

Vi has a macro language.

Eclipse extensions are realized via Java plugins. The extension points can then be assigned to key sequences. In order to create a plugin, an entire Eclipse Java package must to be created and all kinds of non-evident manual actions have to be executed. EASE makes it better with Rhino (Javascript) and Jython integration. Python is supposedly fully integrated since 2017 (not verfied, not investigated). See also section 7.7.1, Integrated Development Environment.

The equivalent of a “package” in Emacs is just a simple file (conventionally with the extension .el (but not necessarily)).

Let’s put it in ~/.emacs.d as ~/.emacs.d/my-file.el. The file contains an interactive function, suitable for assignment to a key sequence:

(defun my-func (arg)
 "Help".
 (interactive "sText: ")
 (insert (concat "//" arg "//"))
 )

To “install” this “package”, add the following code to your .emacs file:

(load-file "~/.emacs.d/my-file.el")

To assign the function my-func() to a key sequence, add the following to your .emacs file:

(global-set-key "C-c uet" 'my-func)

You can also put this in my-file.el for auto-installation of the key sequence shortcut :).

That’s it folks!

12.8. Useful packages

12.8.1. Table editing

Emacs comes with table.el, which allows editing ASCII tables in a WYSIWYG manner.

To recognize tables in a document, enter M-x table-recognize RET. Besides the Table menu there are shortcuts accessible inside table cells with the prefix C-c C-c. C-c C-c C-h inside a table cell show the key bindings.

|:todo:| vi: tables ??
|:todo:| eclipse: tables ??

12.9. Symbol tags

vi supports colon-delimited tags: :tag: (I just don’t know how)

For emacs a generalized tagging, tag navigation and tag search package is available (symbol-tag).

The standard navigation is performed with M-right (previous tag) and M-left (next tag) (see listing 12.1).

listing 12.1 Basic symbol tag navigation
              M-up
           (here tag)
 M-left                 M-right
(any tag)              (any tag)
           M-down
           (here tag)

The here tag is a tag which is directly reachable by navigation keys M-up (previous tag) and M-down (next tag). Initially, the here tag symbol is undefined. The key sequence M-h sets the here tag symbol to here. The here tag symbol can be set to any symbol with C-u M-up or C-u M-down.

M-i inserts a symbol tag, M-k deletes the symbol tag near point.

The alternate delimiter set from a delimiter stack can be activated with C-c C-x. The delimiter stack and quick help is shown with C-c C-d C-v.

An independent delimiter is defined for enclosing symbols at point with M-e (M-x symbol-tag-enclose). The enclosing delimiter can be defined with a prefix arg selecting an entry from the delimiter set menu e.g. C-u 1 3 M-e (see F8).

There are key sequences available for marking the block of lines between two symbol tags with the same symbol (see table 12.1). With a prefix arg, teh tag symbol can be set explicitely.

table 12.1 Mark line block between two symbol tags
Shortcut Command w/first line w/last line
C-c r r M-x symbol-tag-region
C-c r 1 M-x symbol-tag-region-1 yes
C-c r 2 M-x symbol-tag-region-2
yes
C-c r 3 M-x symbol-tag-region-3 yes yes

A grep-find(), which constructs a correctly quoted pattern for symbol tags is available as M-g (M-x symbol-tag-grep-find).

An occur(), which constructs a correctly quoted pattern for symbol tags is available as M-o (M-x symbol-tag-occur).

C-h m shows mode help. In help buffer move to section about symbol-tag minor-mode.

C-h k M-<down> shows help for key bound to next-symbol-tag()

C-h b shows current key bindings. M-x occur RET -symbol-tag RET in buffer *Help* shows keys for symbol movement.

12.10. Directory/filename shortcuts

shortcut description
C-c u d d copy directory of buffer to kill-ring
C-c u d f basename of file, e.g. README-emacs-vi-eclipse.txt
C-u C-c u d f with prefix: full path of file, e.g. /home/da/project/documentation/README-emacs-vi-eclipse.txt
shortcut command
C-c u d d M-x dired-xx-copy-directory-as-kill
C-c u d o M-x dired-xx-copy-directory-as-kill-other-window
C-c u d w M-x dired-xx-copy-directory-as-kill-windos
C-c u d f M-x dired-xx-copy-filename-as-kill