Publi

Creando una configuración personalizada para Emacs. Mi .emacs.d con explicaciones detalladas (II – Edición de código)


Suelo utilizar Emacs para editar código fuente para todos mis programas, tanto proyectos grandes como pequeños. Y, para crear muchos de los ejemplos que pongo en el blog (Aunque a veces la indentación no se copia bien). Por eso, es muy importante, tener herramientas para poder utilizar sin problemas y cómodamente el código en nuestro editor.

En este post, como ya empecé hace unos días (ver aquí Mi configuración personalizada para Emacs, primera parte) seguiré comentando punto por punto mi configuración actual de Emacs, con las utilidades a mi gusto. Aunque la configuración actualizada la tengo en GitHub, vamos a ver con detalle las partes dedicadas a ayuda de edición de código, orientado sobre todo a hacer más llevadera la programación con utilidades que mejoran nuestra experiencia de usuario y sesiones.

init.el

La configuración que muestro aquí está dividida en varios archivos está dividida en múltiples archivos divididos por categorías. En el post anterior vemos más detalles sobre el árbol de directorios y el contenido de init.el así como la forma en la que tenemos que incluir los archivos que presento aquí.

De todas formas, este código puede ser evaluado con M-x eval-expression / M-x eval-region (dependiendo de dónde lo escribamos). Incluso es recomendable abrir un buffer nuevo (o *scratch*) para practicar y probar cosas.

Gestión de sesiones – init-sessions.el

En este archivo:

  • Establecemos configuración de las sesiones y bloqueos. En mi caso, dependiendo del directorio desde el que se abra Emacs. Así como el auto-salvado de la sesión, a los 10 minutos (600 segundos)
  • Sobreescribo funciones de lectura del desktop para mostrar el tiempo invertido en restaurar el desktop.
  • Hacemos que se restauren más aspectos de la sesión de Emacs con el session-mode.
  • Se establecen valores por defecto del tamaño de los historiales que guardará Emacs. No los pongo ilimitados para que se optimice un poco el uso de la memoria y las búsquedas sean más rápidas.
  • Configuramos las copias de seguridad. Éstas utilizarán el modo backup-by-copying, aunque es el más lento, de otro modo, la copia de seguridad se hace renombrando y en algunos sistemas de archivos puede dar problemas. Por otro lado, se mantendrán varias versiones de los archivos y todas las copias de seguridad se harán en el directorio ./.__backups__ dentro del directorio actual. Muchos prefieren guardar las copias de seguridad en otro sitio, podemos darle una ruta absoluta si queremos guardar todas las copias de seguridad juntas.
  • También me gusta la forma en la que Emacs ofrece salvado automático de archivos aunque podremos establecer el directorio que deseemos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
;; From https://github.com/purcell/emacs.d/blob/master/lisp/init-sessions.el
;; Using some settings from https://github.com/alexott/emacs-configs/blob/master/rc/emacs-rc-desktop.el
;; save a list of open files in ~/.emacs.d/.emacs.desktop

(setq-default desktop-missing-file-warning nil)

(setq emacs-sessions-directory (expand-file-name "sessions/" user-emacs-directory))
(setq emacs-desktop-file (concat "emacs_" (secure-hash 'md5 default-directory) ".desktop"))
(setq emacs-desktop-lock (concat "lock_" (secure-hash 'md5 default-directory)))
(setq desktop-path (list emacs-sessions-directory)
      desktop-base-file-name      emacs-desktop-file
      desktop-base-lock-name      emacs-desktop-lock
      desktop-save                t
      desktop-files-not-to-save   "^$" ;reload tramp paths
      desktop-auto-save-timeout 600)
(desktop-save-mode 1)

(defadvice desktop-read (around time-restore activate)
    (let ((start-time (current-time)))
      (prog1
          ad-do-it
        (message "Desktop restored in %.2fms"
                 (float-time (time-subtract (current-time)
                emacs-start-time))))))

(defadvice desktop-create-buffer (around time-create activate)
  (let ((start-time (current-time))
        (filename (ad-get-arg 1)))
    (prog1
        ad-do-it
      (message "Desktop: %.2fms to restore %s"
               (float-time (time-subtract (current-time)
                  emacs-start-time))
               (when filename
         (abbreviate-file-name filename))))))

;;----------------------------------------------------------------------------
;; Restore histories and registers after saving
;;----------------------------------------------------------------------------
(setq-default history-length 1000)
(savehist-mode t)

(require-package 'session)

(setq session-save-file (expand-file-name ".session" user-emacs-directory))
(setq session-name-disable-regexp "\\(?:\\`'/tmp\\|\\.git/[A-Z_]+\'\\)")
(add-hook 'after-init-hook 'session-initialize)

;;----------------------------------------------------------------------------
;; Histories configuration
;;----------------------------------------------------------------------------
;; save a bunch of variables to the desktop file
;; for lists specify the len of the maximal saved data also
(setq desktop-globals-to-save
      (append '((comint-input-ring        . 50)
                (compile-history          . 30)
                desktop-missing-file-warning
                (dired-regexp-history     . 20)
                (extended-command-history . 30)
                (face-name-history        . 20)
                (file-name-history        . 100)
                (grep-find-history        . 30)
                (grep-history             . 30)
                (ido-buffer-history       . 100)
                (ido-last-directory-list  . 100)
                (ido-work-directory-list  . 100)
                (ido-work-file-list       . 100)
                (ivy-history              . 100)
                (magit-read-rev-history   . 50)
                (minibuffer-history       . 50)
                (org-clock-history        . 50)
                (org-refile-history       . 50)
                (org-tags-history         . 50)
                (query-replace-history    . 60)
                (read-expression-history  . 60)
                (regexp-history           . 60)
                (regexp-search-ring       . 20)
                register-alist
                (search-ring              . 20)
                (shell-command-history    . 50)
                tags-file-name
                tags-table-list)))

(when (eval-when-compile (and (>= emacs-major-version 24)
                              (version< emacs-version "24.3.50")
                              ))
  (unless (boundp 'desktop-restore-frames)
    (require-package 'frame-restore)
    (frame-restore)))

;;----------------------------------------------------------------------------
;; Backups and auto-save
;;----------------------------------------------------------------------------
;; Backups management (file~)
(setq backup-by-copying t)
(setq backup-directory-alist '(("." . ".__backups__")))
(setq delete-old-versions t
      kept-new-versions 6
      kept-old-versions 2
      version-control t)

;; Autosave backups management (#file#) Emacs Wiki, https://www.emacswiki.org/emacs/AutoSave
(defconst emacs-tmp-dir (expand-file-name (format "emacs%d" (user-uid)) temporary-file-directory))
(setq auto-save-file-name-transforms
        `((".*" ,emacs-tmp-dir t)))
    (setq auto-save-list-file-prefix
          emacs-tmp-dir)


(myemacs/elapsed-time)
(provide 'init-sessions)

init-cedet.el

EMACS CEDET Screenshot
CEDET (Collection of Emacs Development Environment Tools o Colección de Herramientas de Entorno de Desarrollo de Emacs) es una de las joyas de Emacs que permiten aumentar la funcionalidad de este editor a otro nivel. En CEDET tenemos muchas utilidades que harán que programemos mucho más rápido. Algunos de los módulos que encontramos en CEDET son:

  • Semantic: Analiza nuestro código para ofrecernos autocompletado inteligente, resaltar declaraciones de funciones, buscar implementaciones, navegar dentro de nuestro código, buscar errores, etc.
  • EDE: Emacs Development Environment (Entorno de Desarrollo de Emacs), nos proporciona un entorno de gestión de proyectos.
  • SRE: Gestor de plantillas
  • ECB: Emacs Code Browser (Navegador de Código de Emacs). Nos presentará una configuración de ventanas en la que incluirá un navegador de archivos y directorios, un navegador de objetos dentro de nuestro código y un historial además de la ventana de nuestro código. Es más o menos lo que se ve en la imagen de este apartado.
  • Otros: Podemos instalar una barra de acceso rápido a elementos (Speedbar), tenemos un módulo para crear diagramas (COGRE), y muchas funciones Lisp que pueden utilizar otros módulos para Emacs.

Nuestro archivo init-cedet.el será el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
;; Based on Alex Ott's minimal-cedet-config : https://gist.github.com/alexott/3930120
;; and others

;; Use builtin CEDET instead of installing new CEDET version
(require 'cedet)
;; Load contrib directory
(add-to-list 'load-path (file-name-as-directory (expand-file-name "site-lisp/cedet-contrib/" user-emacs-directory)) "contrib")

;; Workarounds for Emacs < 25
(when (eval-when-compile (version< "25" emacs-version))
  (setq fixes-root-path (file-name-as-directory (expand-file-name "lisp/fixes/" user-emacs-directory)))
  (load-file (concat fixes-root-path "hideif.el")))

;; SemanticDB installed by default
(add-to-list 'semantic-default-submodes 'global-semanticdb-minor-mode t)
;; Buffer parsing when idle
(add-to-list 'semantic-default-submodes 'global-semantic-idle-scheduler-mode 1)
;; Display current function on header
(add-to-list 'semantic-default-submodes 'global-semantic-stickyfunc-mode 1)
;; Highlight the declaration of current function
(add-to-list 'semantic-default-submodes 'global-semantic-highlight-func-mode 1)
;; Display function info in minibuffer
(add-to-list 'semantic-default-submodes 'global-semantic-idle-summary-mode t)
;; srecode!!
(add-to-list 'semantic-default-submodes 'global-srecode-minor-mode t)
;; Show parser status when parsing lasts long
(add-to-list 'semantic-default-submodes 'global-show-parser-state-mode t)
;; Decorates some parts of the file due to the position where we are
(add-to-list 'semantic-default-submodes 'global-semantic-decoration-mode t)
;; Underline in red everything it cannot parse
(add-to-list 'semantic-default-submodes 'global-semantic-show-unmatched-syntax-mode)
;; Most Recently Used tags/functions fast jump
(add-to-list 'semantic-default-submodes 'global-semantic-mru-bookmark-mode)

(setq-default semantic-idle-scheduler-idle-time 5) ;I'm idle when I've been 5 seconds out
(setq-default semantic-idle-scheduler-verbose-flag 't) ;Tell me when you are working

(semantic-mode)

;; These may be automatically required, but I had them from previous versions
(require 'semantic/bovine/c)
(require 'semantic/bovine/gcc)
(require 'semantic/bovine/grammar)
(require 'semantic/bovine/make)
(require 'semantic/bovine/scm)
(require 'semantic/idle)
(require 'semantic/db)
(require 'semantic/ia)
(require 'semantic/analyze)
(require 'eassist)

;; customisation of modes
(defun gasparfm/cedet-hook ()
  (local-set-key [(control return)] 'semantic-ia-complete-symbol-menu)
  (local-set-key "\C-c?" 'semantic-ia-complete-symbol)
  ;;
  (local-set-key "\C-c>" 'semantic-complete-analyze-inline)
  (local-set-key "\C-c=" 'semantic-decoration-include-visit)
  ;; C-c+j = Fast jump
  (local-set-key "\C-cj" 'semantic-ia-fast-jump)
  ;; C-c+q = Show doc
  (local-set-key "\C-cq" 'semantic-ia-show-doc)
  ;; C-c+s Show Summary
  (local-set-key "\C-cs" 'semantic-ia-show-summary)
  ;; C-c+p = Toggle between prototype and function
  (local-set-key "\C-cp" 'semantic-analyze-proto-impl-toggle)
  ;; C-c+m = Switch MRU tags
  (local-set-key "\C-cp" 'semantic-mrub-switch-tags)
  )

(add-hook 'c-mode-common-hook 'gasparfm/cedet-hook)
(add-hook 'lisp-mode-hook 'gasparfm/cedet-hook)
(add-hook 'scheme-mode-hook 'gasparfm/cedet-hook)
(add-hook 'emacs-lisp-mode-hook 'gasparfm/cedet-hook)
(add-hook 'erlang-mode-hook 'gasparfm/cedet-hook)

(add-to-list 'semantic-dependency-system-include-path '/usr/include/c++/5/bits)
(semanticdb-enable-gnu-global-databases 'c-mode t)
(semanticdb-enable-gnu-global-databases 'c++-mode t)

;; SRecode
;; Delete ~/.emacs.d/srecode-map.el if any problems loading
(require 'srecode)
(global-srecode-minor-mode 1)

;; EDE
(require 'ede)
(global-ede-mode 1)
(ede-enable-generic-projects)

(require-package 'ecb)
(setq-default ecb-tip-of-the-day nil)

(myemacs/elapsed-time)
(provide 'init-cedet)

Lo primero que hacemos es cargar el módulo cedet que viene con Emacs. Aunque podemos descargarlo de Internet, con muchos módulos y más completo, el que viene con Emacs suele ser más nuevo y compatible con nuestra versión de Emacs. Puede que si lo descargamos, aunque sea desde la página oficial, tengamos ciertos problemas para echarlo a andar.

Luego cargamos en el load-path de Emacs el contenido de site-lisp/cedet-contrib. Dentro de este directorio (que podemos ver en el GitHub de mi configuración) he incluido algunos archivos que vienen con la instalación original de CEDET y no vienen en el core, pero que son interesantes.

Además, incluyo un archivo hideif.el que suele venir con Emacs y, tiene un bug en versiones inferiores a Emacs 25 (creo que en la 24.5 ya lo arreglaron, pero no llegué a probarlo). CEDET utiliza este módulo internamente y puede provocar algunos avisos, incluso hacer que no inicie Emacs correctamente.

Una vez cargado el módulo, vemos qué partes vamos a configurar. En mi caso, me quedo con Semantic, EDE, SREcode, ECB y EAssist (parte de los módulos de contrib que usan CEDET por debajo).

Semantic, que parsea el contenido de mis archivos de código leyendo variables, funciones, clases, espacios de nombres y demás lo suelo usar para asistirme mientras codifico. Esta asistencia suele ser el autocompletado inteligente, que me da opciones relativas a lo que estoy escribiendo. Puede darme opciones tanto del propio lenguaje como de bibliotecas que esté incluyendo y sean accesibles. Está pensado para C y C++, aunque para otros lenguajes también funciona bien y me permite trabajar rápidamente. Aunque está hecho en un lenguaje interpretado funciona muy rápido, e incluso hay formas de hacer que funcione más rápido aún, ayudándonos de aplicaciones externas, yo prefiero que mi configuración de Emacs sea lo más portable posible, y llevándome el directorio .emacs.d o incluso clonándolo de GitHub sea suficiente. También se usa para que ECB muestre información sobre los elementos que se encuentran en el código y pueda ir directamente a funciones, variables o estructuras determinadas o, por ejemplo, para que cuando programo en C o C++ pueda saltar directamente de un archivo de cabecera a uno de código sin tener que hacerlo a mano, dirigiéndome directamente al número de línea concreto donde está una función, una llamada, etc.

Aunque Semantic tiene muchas posibles configuraciones, en mi configuración personal incluiré:

  • semanticdb-minor-mode. Como parsear archivos de código fuente es una tarea pesada que puede dejar a Emacs colgado durante varios segundos o minutos. Haremos que Semantic sólo lea los archivos cuando haya cosas nuevas, almacenando en caché los elementos que ya ha leído y optimizando así su funcionamiento.
  • global-semantic-idle-scheduler-mode. Analiza archivos cuando no estoy directamente trabajando con Emacs. Porque es muy incómodo que, mientras estás trabajando, el editor se pare y no te deje hacer nada, aunque sea durante unos segundos. Por eso, aunque a veces, cuando utilizamos el autocompletado puede forzarse un parseo de los archivos, es interesante que, mientras no estemos trabajando se vayan completando ciertas partes del mismo. Personalmente, lo suelo configurar con semantic-idle-scheduler-idle-time indicando que se considere que no hago nada cuando lleve 5 segundos sin utilizar Emacs, y semantic-idle-scheduler-verbose-flag para que me indique en pantalla cuándo está trabajando Semantic.
  • global-semantic-stickyfunc-mode coloca en la parte superior del buffer el prototipo de la función dentro de la que estamos. Es muy útil cuando las funciones son muy grandes, o nuestra pantalla muy pequeña, para tener siempre presente el nombre de la función y los argumentos de entrada.
  • global-semantic-highlight-func-mode. Resalta llamadas o declaraciones de funciones mientras tenemos el cursor encima. Así sabemos dónde se llama, y dónde se declara una función.
  • global-semantic-idle-summary-mode. Nos muestra la cabecera de las funciones en el minibuffer ayudándonos a ver los argumentos de una función, método o llamada de un vistazo.
  • srecode-minor-mode. Activa el sistema de plantillas SREcode.
  • global-show-parser-state-mode. Cuando esté realizando un parseo de archivos fuente, decirnos el progreso del parseo en el minibuffer. Siempre es algo más lento decir cuánto lleva completado de una tarea e ir actualizando ese progreso, pero desespera menos al que pacientemente está mirando pasmado la pantalla esperando que se realice la tarea.
  • global-semantic-decoration-mode. Aplica una decoración a cada palabra clave del código.
  • global-semantic-show-unmatched-syntax-mode. Nos avisa cuando hay errores de sintaxis según el parseador. Puede que algo no sea un error de sintaxis propiamente dicho, en códigos muy complejos, tal vez el parser no llegue a lo que nosotros queremos, pero generalmente funciona bien.
  • global-semantic-mru-bookmark-mode. Nos permite saltar entre etiquetas (variables, funciones, etc) para dirigirnos a la parte del código donde se declaran/definen/llaman con M-n, M-p
  • También establecemos algunas teclas rápidas para llamar algunos métodos de semantic. Podemos verlo al final del post, en teclas rápidas y se añaden a un hook de determinados lenguajes.

Tras esto, se añaden algunas características para mejorar el parseo de las bibliotecas de C y C++.

Utilidades de edición (init-editing-utils.el)

Ahora vamos a ver algunas utilidades que nos ayudarán a utilizar nuestro entorno de programación, o configurarlo de manera fina, a nuestro gusto. Nota: El gusto de cada uno puede variar, aunque aquí tenéis un punto de partida.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
;; From : https://github.com/purcell/emacs.d/blob/master/lisp/init-editing-utils.el
;; and others

(require-package 'diminish)
(require-package 'unfill)
(require-package 'focus)

;; Automatic pairs open symbols (, {, [...
;; (when (fboundp 'electric-pair-mode)
;;   (electric-pair-mode))
(when (eval-when-compile (version< "24.4" emacs-version))
  (electric-indent-mode 1))

;;----------------------------------------------------------------------------
;; Some basic preferences
;;----------------------------------------------------------------------------
(setq-default
 blink-cursor-interval 0.4
 bookmark-default-file (expand-file-name ".bookmarks.el" user-emacs-directory)
 buffers-menu-max-size 30
 case-fold-search t
 column-number-mode t
 delete-selection-mode t
 ediff-split-window-function 'split-window-horizontally
 ediff-window-setup-function 'ediff-setup-windows-plain
 indent-tabs-mode t
 make-backup-files t
 auto-save-interval 180                                 ;Auto save every 180 secs
 mouse-yank-at-point t
 save-interprogram-paste-before-kill t
 scroll-preserve-screen-position 'always
 set-mark-command-repeat-pop t
 tooltip-delay 0.5
 truncate-lines nil
 truncate-partial-width-windows nil)

(global-auto-revert-mode)
(setq global-auto-revert-non-file-buffers t
      auto-revert-verbose nil)

(transient-mark-mode t)

;;; Newline behaviour
(defun sanityinc/newline-at-end-of-line ()
  "Move to end of line, enter a newline, and reindent."
  (interactive)
  (move-end-of-line 1)
  (newline-and-indent))

(when (eval-when-compile (string< "24.3.1" emacs-version))
  ;; https://github.com/purcell/emacs.d/issues/138
  (after-load 'subword
    (diminish 'subword-mode)))

;; Some bugs with indent-guide-mode and autocomplete-mode
;; (when (maybe-require-package 'indent-guide)
;;   (add-hook 'prog-mode-hook 'indent-guide-mode)
;;   (after-load 'indent-guide
;;     (diminish 'indent-guide-mode)))

;;(require-package 'nlinum)

(when (require-package 'rainbow-delimiters)
  (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

(when (fboundp 'global-prettify-symbols-mode)
  (global-prettify-symbols-mode))

(require-package 'undo-tree)
(global-undo-tree-mode)
(diminish 'undo-tree-mode)


(require-package 'highlight-symbol)
(dolist (hook '(prog-mode-hook html-mode-hook css-mode-hook))
  (add-hook hook 'highlight-symbol-mode)
  (add-hook hook 'highlight-symbol-nav-mode))
(add-hook 'org-mode-hook 'highlight-symbol-nav-mode)
(after-load 'highlight-symbol
  (diminish 'highlight-symbol-mode)
  (defadvice highlight-symbol-temp-highlight (around sanityinc/maybe-suppress activate)
    "Suppress symbol highlighting while isearching."
    (unless (or isearch-mode
                (and (boundp 'multiple-cursors-mode) multiple-cursors-mode))
      ad-do-it)))

;;----------------------------------------------------------------------------
;; Zap *up* to char is a handy pair for zap-to-char
;;----------------------------------------------------------------------------
(autoload 'zap-up-to-char "misc" "Kill up to, but not including ARGth occurrence of CHAR.")
(global-set-key (kbd "M-Z") 'zap-up-to-char)

;;----------------------------------------------------------------------------
;; Browse kill ring
;;----------------------------------------------------------------------------
(require-package 'browse-kill-ring)
(setq browse-kill-ring-highlight-inserted-item 'pulse)
(setq browse-kill-ring-highlight-current-entry t)
(setq browse-kill-ring-show-preview t)
(setq browse-kill-ring-separator "\f")
(global-set-key (kbd "s-Y") 'browse-kill-ring)
(after-load 'browse-kill-ring
  (define-key browse-kill-ring-mode-map (kbd "C-g") 'browse-kill-ring-quit)
  (define-key browse-kill-ring-mode-map (kbd "M-n") 'browse-kill-ring-forward)
  (define-key browse-kill-ring-mode-map (kbd "M-p") 'browse-kill-ring-previous)
  (define-key browse-kill-ring-mode-map (kbd "<down>") 'browse-kill-ring-forward)
  (define-key browse-kill-ring-mode-map (kbd "<up>") 'browse-kill-ring-previous)
  (define-key browse-kill-ring-mode-map (kbd "<backtab>") 'browse-kill-ring-previous) ;Shift + TAB
  )
(after-load 'page-break-lines
  (push 'browse-kill-ring-mode page-break-lines-modes))

;; Forward yank
(defun yank-pop-forwards (arg)
      (interactive "p")
      (yank-pop (- arg)))
    (global-set-key "\M-Y" 'yank-pop-forwards) ; M-Y (Meta-Shift-Y)

;;----------------------------------------------------------------------------
;; Don't disable narrowing commands
;;----------------------------------------------------------------------------
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-defun 'disabled nil)

;;----------------------------------------------------------------------------
;; Show matching parens
;;----------------------------------------------------------------------------
(show-paren-mode 1)

;;----------------------------------------------------------------------------
;; Expand region
;;----------------------------------------------------------------------------
(require-package 'expand-region)
(global-set-key (kbd "C-=") 'er/expand-region)

;;----------------------------------------------------------------------------
;; Don't disable case-change functions
;;----------------------------------------------------------------------------
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)

;;----------------------------------------------------------------------------
;; Don't disable these functions
;;----------------------------------------------------------------------------
(put 'scroll-left 'disabled nil)
(put 'eval-expression 'disabled nil)

;;----------------------------------------------------------------------------
;; Rectangle selections, and overwrite text when the selection is active
;;----------------------------------------------------------------------------
(cua-selection-mode t)                  ; for rectangles, CUA is nice


;; Dont delete selected text when pressing key. C-w
(setq delete-selection-mode nil)

;;----------------------------------------------------------------------------
;; Handy key bindings
;;----------------------------------------------------------------------------
(global-set-key (kbd "C-.") 'set-mark-command)
(global-set-key (kbd "C-x C-.") 'pop-global-mark)

;; (when (maybe-require-package 'avy)
;;   (global-set-key (kbd "C-;") 'avy-goto-word-or-subword-1))

(require-package 'multiple-cursors)
;; multiple-cursors
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-+") 'mc/mark-next-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
;; From active region to multiple cursors:
(global-set-key (kbd "C-c c r") 'set-rectangular-region-anchor)
(global-set-key (kbd "C-c c c") 'mc/edit-lines)
(global-set-key (kbd "C-c c e") 'mc/edit-ends-of-lines)
(global-set-key (kbd "C-c c a") 'mc/edit-beginnings-of-lines)


;; Train myself to use M-f and M-b instead
(global-unset-key [M-left])
(global-unset-key [M-right])



(defun kill-back-to-indentation ()
  "Kill from point back to the first non-whitespace character on the line."
  (interactive)
  (let ((prev-pos (point)))
    (back-to-indentation)
    (kill-region (point) prev-pos)))

(global-set-key (kbd "S-<backspace>") 'kill-back-to-indentation)

;;----------------------------------------------------------------------------
;; Page break lines
;;----------------------------------------------------------------------------
(require-package 'page-break-lines)
(global-page-break-lines-mode)
(diminish 'page-break-lines-mode)

;;----------------------------------------------------------------------------
;; Shift lines up and down with M-up and M-down. When paredit is enabled,
;; it will use those keybindings. For this reason, you might prefer to
;; use M-S-up and M-S-down, which will work even in lisp modes.
;;----------------------------------------------------------------------------
(require-package 'move-dup)
;(global-set-key [M-up] 'md/move-lines-up)
;(global-set-key [M-down] 'md/move-lines-down)
;(global-set-key [M-S-up] 'md/move-lines-up)
;(global-set-key [M-S-down] 'md/move-lines-down)

(global-set-key (kbd "C-c d") 'md/duplicate-down)
(global-set-key (kbd "C-c D") 'md/duplicate-up)

;;----------------------------------------------------------------------------
;; Fix backward-up-list to understand quotes, see http://bit.ly/h7mdIL
;;----------------------------------------------------------------------------
(defun backward-up-sexp (arg)
  "Jump up to the start of the ARG'th enclosing sexp."
  (interactive "p")
  (let ((ppss (syntax-ppss)))
    (cond ((elt ppss 3)
           (goto-char (elt ppss 8))
           (backward-up-sexp (1- arg)))
          ((backward-up-list arg)))))

(global-set-key [remap backward-up-list] 'backward-up-sexp) ; C-M-u, C-M-up


;;----------------------------------------------------------------------------
;; Cut/copy the current line if no region is active
;;----------------------------------------------------------------------------
(require-package 'whole-line-or-region)
(whole-line-or-region-mode t)
(diminish 'whole-line-or-region-mode)
(make-variable-buffer-local 'whole-line-or-region-mode)

(defun suspend-mode-during-cua-rect-selection (mode-name)
  "Add an advice to suspend `MODE-NAME' while selecting a CUA rectangle."
  (let ((flagvar (intern (format "%s-was-active-before-cua-rectangle" mode-name)))
        (advice-name (intern (format "suspend-%s" mode-name))))
    (eval-after-load 'cua-rect
      `(progn
         (defvar ,flagvar nil)
         (make-variable-buffer-local ',flagvar)
         (defadvice cua--activate-rectangle (after ,advice-name activate)
           (setq ,flagvar (and (boundp ',mode-name) ,mode-name))
           (when ,flagvar
             (,mode-name 0)))
         (defadvice cua--deactivate-rectangle (after ,advice-name activate)
           (when ,flagvar
             (,mode-name 1)))))))

(suspend-mode-during-cua-rect-selection 'whole-line-or-region-mode)




(defun sanityinc/open-line-with-reindent (n)
  "A version of `open-line' which reindents the start and end positions.
If there is a fill prefix and/or a `left-margin', insert them
on the new line if the line would have been blank.
With arg N, insert N newlines."

  (interactive "*p")
  (let* ((do-fill-prefix (and fill-prefix (bolp)))
     (do-left-margin (and (bolp) (> (current-left-margin) 0)))
     (loc (point-marker))
     ;; Don't expand an abbrev before point.
     (abbrev-mode nil))
    (delete-horizontal-space t)
    (newline n)
    (indent-according-to-mode)
    (when (eolp)
      (delete-horizontal-space t))
    (goto-char loc)
    (while (> n 0)
      (cond ((bolp)
         (if do-left-margin (indent-to (current-left-margin)))
         (if do-fill-prefix (insert-and-inherit fill-prefix))))
      (forward-line 1)
      (setq n (1- n)))
    (goto-char loc)
    (end-of-line)
    (indent-according-to-mode)))

;;----------------------------------------------------------------------------
;; Random line sorting
;;----------------------------------------------------------------------------
(defun sort-lines-random (beg end)
  "Sort lines in region randomly."
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (let ;; To make `end-of-line' and etc. to ignore fields.
          ((inhibit-field-text-motion t))
        (sort-subr nil 'forward-line 'end-of-line nil nil
                   (lambda (s1 s2) (eq (random 2) 0)))))))




(require-package 'highlight-escape-sequences)
(hes-mode)

(require-package 'guide-key)
(setq guide-key/guide-key-sequence '("C-x" "C-c" "C-x 4" "C-x 5" "C-c ;" "C-c ; f" "C-c ' f" "C-x n" "C-x C-r" "C-x r" "M-s" "C-h"))
(add-hook 'after-init-hook
          (lambda ()
            (guide-key-mode 1)
            (diminish 'guide-key-mode)))

;;----------------------------------------------------------------------------
;; More useful things
;;----------------------------------------------------------------------------
(set-default 'truncate-lines t)
(setq show-trailing-whitespace nil)
(setq site-lisp-path (file-name-as-directory (expand-file-name "site-lisp/" user-emacs-directory)))

(require-package 'fill-column-indicator)

;; ;; Global-FCI-mode can cause problems, like minibuffer with fci or information windows
;; ;; drawing incorrectly.
(define-globalized-minor-mode global-fci-mode fci-mode (lambda () (fci-mode 1)))
(defvar fci-mode nil)
;; (global-fci-mode 1)
(add-hook 'prog-mode-hook 'my/fci-mode-stuff)

(defun my/fci-mode-stuff ()
    (fci-mode 1)
    (setq fci-rule-color "dim gray")
    (setq fci-rule-width 2)
    (setq fci-rule-column 130)
    ;; Workaround because of implementation of show-trailing-whitespace https://github.com/alpaker/Fill-Column-Indicator/blob/master/fill-column-indicator.el
    (setq whitespace-style '(face trailing))
    ;; fci-mode not compatible with non-nil values of hl-line-sticky-flag
    (setq hl-line-sticky-flag nil))

;; (set-fill-column 130)
;; (global-whitespace-mode)
;;
;; Word Count Mode with Goals. Can be activated, Run in Modeline
(require-package 'wc-mode)
; hideshowvis for hs-mode
;(require-package 'hideshowvis)
(dolist (hook (list 'emacs-lisp-mode-hook
                    'java-mode-hook
                    'lisp-mode-hook
                    'perl-mode-hook
                    'hs-mode-hook
                    'c-mode-common-hook))
  (add-hook hook 'hs-minor-mode))
;; From EmacsWiki expand hidden block when searching for line
(defadvice goto-line (after expand-after-goto-line
                            activate compile)
  "hideshow-expand affected block when using goto-line in a collapsed buffer"
  (save-excursion
    (hs-show-block)))

;; Echo keystrokes
(setq echo-keystrokes 0.1)

;; Copy/Paste behaviour. Use X clipboard.
(setq x-select-enable-primary t)
(setq x-select-enable-clipboard nil)

;; Emacs Scroll like any other editor kaka pedo culo pis
(setq scroll-step            1
      scroll-conservatively  10000)
;; Show line numbers when using go-to line when line numbers are not enabled
;; Stolen from http://whattheemacsd.com/key-bindings.el-01.html
(global-set-key [remap goto-line] 'goto-line-with-feedback)

(defun goto-line-with-feedback ()
  "Show line numbers temporarily, while prompting for the line number input"
  (interactive)
  (unwind-protect
      (progn
        (linum-mode 1)
        (goto-line (read-number "Goto line: ")))
    (linum-mode -1)))

;; Delete trailing whitespace before saving fil
(add-hook 'before-save-hook 'delete-trailing-whitespace)

;;----------------------------------------------------------------------------
;; Key definitions
;;----------------------------------------------------------------------------
(global-set-key (kbd "RET") 'newline-and-indent)
(global-set-key (kbd "s-<return>") 'sanityinc/newline-at-end-of-line)

(global-set-key (kbd "C-<up>") 'backward-paragraph)
(global-set-key (kbd "C-<down>") 'forward-paragraph)
(global-set-key (kbd "C-<left>") 'backward-word)
(global-set-key (kbd "C-<right>") 'forward-word)

(global-set-key [(s-backspace)] 'undo)
(global-set-key [(s-S-backspace)] 'redo) ;Meta -Shift-Backspace
(global-set-key (kbd "C-o") 'sanityinc/open-line-with-reindent)

;; Mouse horizontal scrolling (in case your mouse has horizontal scroll)
(global-set-key [mouse-6] 'scroll-right)
(global-set-key [mouse-7] 'scroll-left)

;; Sometimes my laptop can't autoindent
(global-set-key (kbd "C-M-º") 'indent-region)

;; hs-mode key bindings I like
(global-set-key (kbd "M-+") 'hs-show-block)
(global-set-key (kbd "M--") 'hs-hide-block)

;; Join lines on M-j
(global-set-key (kbd "M-j") (lambda () (interactive) (join-line -1)))

;; Focus mode toggle
(global-set-key (kbd "s-º") (lambda () (interactive) (focus-mode 'toggle)))

;; Browse kill ring
(global-set-key (kbd "C-c k") 'browse-kill-ring)

;; Highlight symbol
(global-set-key (kbd "M-s-h") 'highlight-symbol)

;; CUA for rectangular selections
(global-set-key (kbd "M-RET") 'cua-rectangle-mark-mode)

;; Smarter move to the beginning of the line
;; remap C-a or to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
                'sacha/smarter-move-beginning-of-line)

(myemacs/elapsed-time)
(provide 'init-editing-utils)

Ahora unas cuantas explicaciones sobre lo que se ha hecho en este archivo:

  • Se activa el modo diminish, que nos ayuda a mantener limpia la modeline. Como vemos, en la modeline se muestran los modos que hay activados, y cada vez tenemos más minor-modes activados, que añaden pequeñas funcionalidades a Emacs. En este caso, hay muchos modos, que si no aparecen, no pasa nada. Así ocultamos algunos, como undo-tree que estará siempre activado.
  • Unfill, combina párrafos o regiones enteras (texto seleccionado) a una sola línea. Al contrario que fill mode que viene con Emacs. Podemos usarlo llamando M-x unfill-paragraph / unfill-region / unfill-toggle
  • Focus mode resalta el párrafo actual. Nos ayuda a centrarnos en una parte del código a medida que nos vamos moviendo. También disponemos entre otras utilidades de M-x focus-pin / focus-unpin que resaltan una región del código de forma permanente.
  • Activa electric-indent-mode para anidar código automáticamente al pulsar enter.
  • Activa auto-revert-mode que recarga automáticamente archivos modificados fuera de Emacs. Es muy útil para ver logs (como auto-revert-tail-mode) entre muchos otros casos.
  • Activa transient-mark-mode para poder seleccionar texto con C-SPC
  • Subword mode no está activado por defecto. Nos ayudará a saltar entre sub-palabras dentro de una frase. Por ejemplo, si creamos FuncionConUnNombreMuyLargo o funcion_con_un_nombre_muy_largo nos permitirá dirigirnos a cada una de las palabras con Control+Flechas.
  • Activa rainbow-delimiters que coloreará llaves, corchetes, paréntesis y demás de diferente color mientras programamos y los casará con sus correspondientes, para que no nos liemos mucho.
  • Prettify-symbols-mode permite cambiar el estilo o la representación de ciertos símbolos. Por ejemplo, cuando escribimos lambda() pone λ, sin cambiar el código, sólo cambia la visualización.
  • ¡Undo-tree es de mis preferidos! Si estás harto o harta de cómo Emacs gestiona el deshacer/rehacer, ¡este es tu modo! Nos muestra un árbol de modificaciones de nuestro código en el que podremos regresar a un estado anterior o, incluso si hemos deshecho cambios y hecho modificaciones, podremos volver a uno de los estados anteriores navegando entre ramas. Se activa con C-x u (como el deshacer normal), podemos navegar con las flechas y salir con la q.
  • highlight-symbol resalta el símbolo bajo el cursor. Aunque utilizo Semantic para navegar ṕor los símbolos con M-p y M-s, puedo utilizar M-s-h para resaltar el símbolo. (Configurado en las teclas rápidas).
  • Browse-kill-ring nos permite navegar por el portapapeles. Así para pegar un texto copiado anteriormente no tendremos que pulsar C-y y luego M-y hasta dar con el que queremos, podemos disponer de un menú interactivo y una previsualización muy chula gracias a browse-kill-ring-highlight-inserted-item, browse-kill-ring-highlight-current-entry, browse-kill-ring-show-preview y browse-kill-ring-separator
  • Previene la desactivación de los narrow-commands. Éstos permiten mostrar sólo parte del código, sin borrarlo. Es accesible desde C-x n n (para mostrar sólo la región seleccionada), C-x n d (para mostrar la función seleccionada) y C-x n w (para mostrar todo de nuevo).
  • Activa show-paren-mode, que muestra los paréntesis, llaves o corchetes que casan con el carácter actual. Junto con rainbow-delimiters son una joya para la edición de código.
  • Activa expand-region, que nos permitirá expandir y contraer la región seleccionada con C-= y C-0.
  • No desactiva upcase-region y downcase region para poner el texto seleccionado en mayúsculas (C-x C-u) o minúsculas (C-x C-l)
  • No desactiva el scroll lateral (C-x ). Eso sí, es incompatible con fci-mode.
  • No desactiva eval-expression (M-:)
  • Activa el cua-mode para hacer selecciones rectangulares. Yo lo activo con M-RET.
  • Evita que eliminemos texto cuando tenemos una selección abierta y pulsamos una tecla. Por ejemplo Cuando hacemos Control+Espacio y seleccionamos y luego escribimos una letra. Definiendo delete-selection-mode a nil no se borrarán las regiones.
  • Activamos multiple-cursors para trabajar en varios lugares a la vez. Podemos navegar con varias teclas que explico al final del post. Es complicado, pero cuando le coges el truco está muy bien.
  • Activamos page-break-lines y lo ocultamos. Este modo dibuja una línea horizontal cuando encuentra saltos de página (representados por ^L). Por cierto, para insertar un salto de página debemos pulsar C-q C-l. Tenemos formas de navegar por páginas, pero no lo uso demasiado. Sobre todo me gusta para la representación de los separadores del kill-ring con la extensión mencionada anteriormente.
  • Modo whole-line-or-region, hace que operaciones como copiar y cortar que afectan a regiones, o selecciones de texto, si no hay texto seleccionado afecten a la línea actual. Y como este modo no es compatible con CUA, lo desactivamos cuando utilizamos la selección rectangular.
  • Modo highlight-escape-sequences para resaltar las secuencias de escape como \n, \r, \t…
  • Modo guide-key que nos presentará ayuda sobre las teclas y sus funciones cuando empecemos a teclear una combinación de teclas como C-x C-c y demás. Podemos configurar el disparo de la ayuda con la combinación de teclas que deseemos.
  • Modo fill-column-indicator muestra una línea vertical en la columna 130, aunque podemos cambiar la columna. Lo malo de este modo es que no es compatible con muchas extensiones de Emacs. Actualmente le estoy dando una oportunidad, pero muchas veces suelo desactivarlo a mano.
  • Modo wc (Word count) que cuenta palabras dentro del buffer. Lo podemos activar a mano con M-x. Está bien, pero me llena la modeline de letras y la mayoría de las veces no me interesa. Adedmás, siempre podemos hacer M-x count-words.
  • Modo hs. Sirve para plegar el código, ocultando fragmentos que no nos interesan. Con M-+ y M– podemos plegar el código entre llaves, incluso funciones o clases enteras para visualizar en la pantalla sólo lo que necesitamos. Además, si utilizamos goto-line para ir a una línea determinada o hacemos una búsqueda dentro de un código oculto, éste se expandirá automáticamente.
  • Cuando utilizamos goto-line, mostramos los números de línea aunque estén desactivados.
  • Elimina los espacios (o los retornos de carro) sobrantes de los buffers antes de salvarlos. Eso nos ahorrará mucho tiempo, salvaremos archivos más pequeños y nos quitará muchos problemas.

Definimos algunas funciones nuevas con utilidades:

  • newline-at-end-of-line : Salta al fin de la línea, y crea una nueva línea. Una alternativa más corta que pulsar la tecla Fin y luego Enter. (La colocaremos en la tecla con s-RET).
  • yank-pop-forwards : Navega hacia atrás por el kill-ring. Es muy útil porque a veces queremos pegar un texto copiado hace mucho tiempo y pegamos, pegamos y pegamos y de repente nos pasamos y tenemos que dar la vuelta por todo el kill-ring para encontrar el texto. Con esta función podemos avanzar en dirección contraria.
  • sort-lines-random : Ordena aleatoriamente las líneas de una región o de un buffer. Podemos llamarla con M-x.
  • Redefinimos la tecla inicio a la función sacha/smarter-move-beginning-of-line. La primera vez que vamos al principio de la línea se hace al primer carácter escrito, por lo que si tenemos una línea indentada podemos acceder directamente a lo importante.

También definimos algunos valores de configuración como por ejemplo:

  • El tiempo de parpadeo del cursor (blink-cursor-interval)
  • Mostrar el número de columna (con column-number-mode)
  • Activamos la creación de archivos de backup (con make-backup-files)
  • Definimos el tiempo de autosalvado a 180 segundos (con auto-save-interval)
  • Hacemos que el pegado sea en la posición del cursor (con mouse-yank-at-point)
  • Activamos el truncado de líneas (con truncate-lines a ‘t)
  • No mostramos los espacios al final de línea (con show-trailing-whitespace a nil).
  • Y muchas más.

Autocompletado


Algo básico en cualquier editor de código es que éste nos ayude a escribir. El desarrollo de un programa es algo muy duro para nosotros (que sea divertido es otra cosa) y actualmente tenemos ordenadores muy potentes por lo que podemos aprovechar esa potencia para evitarnos buscar y tener que recordar miles de cosas o, aunque las recordemos, al menos que sea rápido escribirlas, porque a veces hay funciones, variables o tipos con nombres muy largos que tenemos que escribir una y otra vez.

Así que, es importante contar con un buen sistema de autocompletado. En Emacs, disponemos, entre otros de auto-complete-mode y company-mode, al menos son los más grandes. A mí me gusta auto-complete-mode y este será mi fichero init-auto-complete.el:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
;; Auto-complete basic configuration.
;; We'll find more specific configuration in language files
(require 'auto-complete)
(require 'auto-complete-config)
(global-auto-complete-mode)
(setq ac-comphist-file (expand-file-name
              "ac-comphist.dat" user-emacs-directory))

;; (add-to-list 'ac-dictionary-directories (expand-file-name
;;                   "~/.emacs.d_new/elpa/auto-complete-20170124.1845/dict"))

;;a word must be 3 chars long before completition begins
(setq-default ac-auto-start 2)
(set-default 'ac-sources '(ac-source-abbrev ac-source-words-in-same-mode-buffers ac-source-dictionary ac-source-words-in-buffer))
(setq-default ac-ignore-case 'smart)
;; Do What I Mean mode - Changes TAB behaviour depending on context
(setq-default ac-dwim t)
(setq ac-quick-help-delay 1)
;; Limit candidate limit
(setq ac-candidate-limit 400)
;; Allow searches
(setq ac-use-menu-map t)
(setq ac-candidate-menu-min 0)

(defun ac-emacs-lisp-mode-setup ()
  (setq ac-sources (append
                    '(ac-source-dictionary
                      ac-source-features
                      ac-source-functions
                      ac-source-variables
                      ac-source-symbols)
                                        ac-sources))

  (setq ac-omni-completion-sources
        '(("\\<featurep\s+'" ac+-source-elisp-features)
          ("\\<require\s+'"  ac+-source-elisp-features)
          ("\\<load\s+""    ac-source-emacs-lisp-features))))

(add-hook 'emacs-lisp-mode-hook 'ac-emacs-lisp-mode-setup)

(defun ac-eshell-mode-setup ()
    (auto-complete-mode 1)
  (setq ac-sources (append '(ac-source-abbrev
                             ac-source-words-in-same-mode-buffers
                             ac-source-files-in-current-dir)
                           ac-sources)))

(add-hook 'eshell-mode-hook 'ac-eshell-mode-setup)


(myemacs/elapsed-time)
(provide 'init-auto-complete)

En este fichero defino sólo la parte más básica. Cada lenguaje irá introduciendo sus propias formas de autocompletado. Por ejemplo C y C++ explorarán archivos fuente con Semantic y lo mezclarán con información sobre las bibliotecas; Lisp tendrá muchas funciones y símbolos definidas, otros lenguajes utilizarán parte de sus manuales para completar palabras, etc. Pero en este fichero sólo incluyo la configuración por defecto de auto-complete, lo activo globalmente, estblezco el fichero de historial y defino algunas preferencias:

  • El auto completado se dispara automáticamente al escribir 2 caracteres. (ac-auto-start)
  • Se buscarán posibilidades de autocompletado en abbrev (ac-source-abbrev), características de lisp (ac-source-features), palabras de buffers del mismo modo que el actual (ac-source-words-in-same-mode-buffers), palabras de diccionario (ac-source-dictionary) y palabras del propio buffer (ac-source-words-in-buffer)
  • Se establece una política inteligente para las mayúsculas y minúsculas en las búsquedas (ac-ignore-case ‘smart) con lo que no tendremos que preocuparnos por ello.
  • Do What I Mean Mode. Altera el comportamiento de la tecla TAB dependiendo del contexto en el que estemos, lo que la hace más intuitiva. (ac-dwim t)
  • Retrasa la aparición del popup de ayuda a 1 segunto (ac-quick-help-delay 1). A veces con menos retraso puede causar problemas porque tarde en salir menos que la ventana de las opciones de autocompletado.
  • Limitamos el número de candidatos a mostrar (ac-candidate-limit)
  • Nos permite filtrar los resultados del menú de autocompletado con C-s (ac-use-menu-map)
  • El mínimo de candidatos para mostrar el menú es 1 (ac-candidate-menu-min)
  • Adicionalmente se establecen fuentes de autocompletado para Lisp y Eshell

En el próximo post veremos características personalizadas para lenguajes de programación. En los lenguajes incluiré C, C++, PHP, Python, Javascript, Ruby, HTML, SQL, CSS, LUA y alguno más.

Teclas rápidas


Estas son algunas de las teclas rápidas que se han establecido en este post. En el último post de la serie haré un resumen de todas las teclas rápidas, para tenerlas a modo de chuleta rápida:

  • Control-RET (Control + Enter) [Semantic]: Menú de autocompletado de Semantic (en lugar del menú del modo auto-complete)
  • C-c ? [Semantic] : Muestra en un buffer aparte todas las posibilidades de autocompletar de una etiqueta. Muestra también cierta ayuda en línea de cada etiqueta.
  • C-c > [Semantic] : Muestra en un buffer aparte las posibilidades de autocompletar sin ayuda y todo revuelto.
  • C-c = [Semantic] : Visita el archivo incluido.
  • C-c j [Semantic] : Salta a la línea donde se declara una función. Hace un efecto visual con el salto indicándonos la cabecera, inicio y final de la función.
  • C-c q [Semantic] : Visualiza la documentación de las funciones. Por ejemplo con comentarios de Doxygen
  • C-c s [Semantic] : Muestra un resumen en el minibuffer de llamadas a funciones o métodos.
  • C-c p [Semantic] : Salta al prototipo de la función.
  • C-c m [Semantic] : Salta a una etiqueta determinada
  • M-Z (Alt + Shift + Z) : Borra hasta el carácter indicado.
  • s-y (Meta + y) / C-c k: Activa el navegador del portapapeles para pegar texto de forma más interactiva y precisa.
  • M-Y (Meta + Shift + Y): Si estamos navegando por el kill-ring a la antigua usanza (C-y M-y M-y…) con M-Y navegamos por el ring hacia atrás.
  • C-= (Control =): Expande el texto seleccionado. Nos permite seleccionar una región más grande, delimitada por paréntesis, llaves, corchetes, sentencias, etc.
  • C-0 (Control 0): Encoge el texto seleccionado con los mismos criterios de antes.
  • S-backspace (Shift + retroceder) : Borra la línea actual hasta la indentación.
  • C-c d: Clona la línea actual en la línea siguiente.
  • C-c D: Clona la línea actual en la línea anterior.
  • s-RET (Meta + Enter): Hace que estemos donde estemos en la línea (podemos estar al principio o en mitad), saltemos de línea. Sería como ir al final de la línea y pulsar Enter.
  • C-<up> (Control + arriba): Retrocede un párrafo.
  • C-<down> (Control + abajo): Avanza un párrafo.
  • C-<left> (Control + izquierda): Retrocede una palabra.
  • C-<right> (Control + derecha) Retrocede una palabra.
  • s-backspace (Meta + retroceder): Deshacer (lo que en el Emacs de siempre era C-x u).
  • s-S-backspace (Meta + Shift + retroceder): Rehacer
  • Los ratones que tienen scroll horizontal pueden usarlo.
  • C-M-º (Control + Alt + º): Indentar automáticamente la región. Porque muchas veces C-M-\ no funciona correctamente y porque en los teclados en español podemos pulsar esta combinación con una sola mano.
  • M-+ (Alt + +) : Mostrar un bloque previamente ocultado. Estos bloques pueden ser contenidos de funciones, bucles, comentarios, etc.
  • M– (Alt + -) : Ocultar un bloque.
  • M-j (Alt + j) : Unir líneas, lo contrario de un Enter que puede separarlas.
  • s-º (Meta + º) : Activa el modo focus.
  • M-s-h (Alt + Meta + h) : Resalta o elimina el resaltado del símbolo bajo el cursor.
  • M-RET (Alt + Enter) : Selección rectangular CUA.

Teclas para trabajar con varios cursores a la vez

Los cursores múltiples nos permiten editar varios lugares dentro de un buffer. Son muy útiles cuando insertamos o eliminamos trazas, cuando tenemos que escribir o borrar el mismo texto en varias regiones del código sin tener que ir al buscar y reemplazar varias veces o simplemente cuando queremos sorprender a las visitas o a los que nos miran por encima del hombro cuando estamos trabajando.
En mi configuración de Emacs podemos utilizar las siguientes teclas (algunas de ellas sacadas de la página oficial de la extensión multiple-cursors de Emacs).
Primero debemos seleccionar una región, puede ser una palabra o un fragmento, ya lo hagamos con el ratón o con C-SPC. Luego pulsamos:

  • C-< (Control + <) : Para crear un cursor en la réplica anterior al texto seleccionado.
  • C-> o C-+ (Control + > o Control + «+») : Para crear un cursor en la siguiente réplica al texto seleccionado.
  • C-c C-< : Para crear un cursor en todas las réplicas del texto seleccionado.

También podemos colocar cursores con el ratón si pulsamos s- o lo que es lo mismo la tecla meta o tecla Windows y luego hacer click en algún punto del buffer. Cuando tengamos los cursores podemos escribir cualquier texto y se replicará en cada uno de los cursores, y para insertar una nueva línea podemos pulsar C-j. Los cursores desaparecerán al pulsar Enter o C-g.

Otras opciones que tenemos disponibles son:

  • C-c c r (Control+c, c, r): Para seleccionar regiones rectangulares.
  • C-c c c : Editar las líneas de la región

Foto principal: unsplash-logoCaspar Rubin

También podría interesarte....

There are 11 comments left Ir a comentario

  1. Pingback: Creando una configuración personalizada para Emacs. Mi .emacs.d con explicaciones detalladas (II – Edición de código) | PlanetaLibre /

  2. nasciiboy /
    Usando Mozilla Firefox Mozilla Firefox 57.0 en Linux Linux

    genial, utilizas bastantes extenciones, antes utilizaba ivy para navegar por el anillo de la muerte (no recuerdo por que lo abandone) asi que browse-kill-ring me viene de maravilla + undo-tree que mola bastante, a modo de trueque te dejo dos configuraciones que tengo y no incluyes

    ;; para ver ficheros abiertos recientemente
    (require ‘recentf)
    (recentf-mode t)
    (setq recentf-max-saved-items 200)
    (global-set-key (kbd «C-c o») ‘recentf-open-files)

    ;; Wind Move movimiento entre ventanas
    (global-set-key [s-left] ‘windmove-left)
    (global-set-key [s-right] ‘windmove-right)
    (global-set-key [s-up] ‘windmove-up)
    (global-set-key [s-down] ‘windmove-down)
    ;; atajos para emacs cli
    (global-set-key (kbd «C-c «) ‘windmove-left)
    (global-set-key (kbd «C-c «) ‘windmove-right)
    (global-set-key (kbd «C-c «) ‘windmove-up)
    (global-set-key (kbd «C-c «) ‘windmove-down)

    1. nasciiboy /
      Usando Mozilla Firefox Mozilla Firefox 57.0 en Linux Linux

      uuu, el editor de texto se comio unas etiquetas de mayor que, menor que en atajos de windmove, son «menor que» + flecha + «mayor que»

      1. Gaspar Fernández / Post Author
        Usando Mozilla Firefox Mozilla Firefox 57.0 en Ubuntu Linux Ubuntu Linux

        WordPress parece que se ha comido todo lo que hay entre «menor que» y «mayor que» porque se creería que estabas inyectando HTML o algo.

        Gracias por aclararlo 🙂

    2. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 57.0 en Ubuntu Linux Ubuntu Linux

      Me alegro de que te sirvan estas extensiones. A mí llevan mucho tiempo haciéndome la vida más fácil.

      El tema de windmove y recentf lo tengo en el post anterior: https://poesiabinaria.net/2017/12/creando-una-configuracion-personalizada-emacs-emacs-d-explicaciones-detalladas-i-configuracion-general/ junto con muchas otras cosas. Pero te agradezco que lo pongas también por aquí, que son extensiones muy útiles.

      Para windmove a mí me gusta la combinación M-[arrow], vamos la tecla Alt y las flechas y estoy muy acostumbrado, aunque hay otra extensión muy chula que es switch-window que hace que cuando pulses C-x o y haya varias opciones para cambiar de ventana te ponga en pantalla las opciones en lugar de pasar por todas las ventanas.

      Aunque es cierto que algunos terminales no soportan las «flechas modificadas» y vienen muy bien los atajos de C-c FLECHA. Los incluiré en el GitHub ¡¡Gracias!!

  3. nasciiboy /
    Usando Mozilla Firefox Mozilla Firefox 57.0 en Linux Linux

    a ti!, si, luego que revisite el primer post vi el windmove activando las teclas por defecto, ja, ja, el alzheimer

    el M-[flecha] lo tengo en la terminal grafica (tilix) para hacer los saltos entre paneles(?), en un tty del super ni se entera que existe

  4. Gaspar Fernández / Post Author
    Usando Mozilla Firefox Mozilla Firefox 57.0 en Linux Linux

    Cierto. puede ser incompatible con algunos entornos. Y es precisamente la magia de Emacs, que podemos cambiar las teclas a nuestro gusto. Lo del super es verdad que no se entera en un tty, más de una vez me ha tocado y he tenido que estar M-x [a ver cómo se llamaba el comando……, jejeje]

    Gracias por tu aportación ! 🙂

  5. darien /
    Usando Mozilla Firefox Mozilla Firefox 56.0 en Windows Windows NT

    ¿cómo mostrar loa archivos ocultos con EDE? es decir los que comienzan con «.»

  6. OKBet /
    Usando Google Chrome Google Chrome 118.0.0.0 en Windows Windows NT

    Your article is a perfect article without a hitch. Thank you. My site: League of Legends

  7. CiVault /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    This is a great and interesting article that is very specifying theme with a specific website modified and existing template it is very ideas and complete info.
    Google Maps Citations

  8. https://www.drywallbaltimore.com /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    I appreciate the detailed explanations you’re providing. Looking forward to learning more about your personalized configuration.

Leave a Reply