Publi

Creando una configuración personalizada para Emacs. Mi .emacs.d con explicaciones detalladas (III – Lenguajes de programación)

Lenguajes de programación en Emacs

Seguimos con la serie de posts sobre mi configuración de Emacs. Hoy toca el turno de los lenguajes de programación y de cómo tengo Emacs configurado para soportarlos. En concreto, mi trabajo diario se centra en C, C++, PHP, Python y Bash, aunque me preocupo por el soporte de Emacs Lisp y de algún que otro lenguaje que utilizo de forma esporádica.

Os dejo aquí enlaces a las dos partes anteriores:

Como habéis podido observar tengo la configuración dividida en varios archivos. En la configuración particular de cada lenguaje tendremos cosas como el autocompletado, coloreado, anidado, navegación en el código o plugins que necesitamos activar o desactivar en algunos casos. Todo ello, incorporado en Emacs para que funcione de forma automática.

Compilaciones

Aquí defino algunas directivas para poder lanzar la compilación de un programa. Unas funciones muy sencillas para poder lanzar un Make sobre el código que estoy editando.

init-compile.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
;; From: https://github.com/purcell/emacs.d/blob/master/lisp/init-compile.el
(setq-default compilation-scroll-output t)

(require-package 'alert)

;; Customize `alert-default-style' to get messages after compilation

(after-load 'compile
  (add-hook 'compilation-finish-functions
            'sanityinc/alert-after-compilation-finish))

(after-load 'compile
  (defadvice compilation-start (after sanityinc/save-compilation-buffer activate)
    "Save the compilation buffer to find it later."
    (setq sanityinc/last-compilation-buffer next-error-last-buffer))

  (defadvice recompile (around sanityinc/find-prev-compilation (&optional edit-command) activate)
    "Find the previous compilation buffer, if present, and recompile there."
    (if (and (null edit-command)
             (not (derived-mode-p 'compilation-mode))
             sanityinc/last-compilation-buffer
             (buffer-live-p (get-buffer sanityinc/last-compilation-buffer)))
        (with-current-buffer sanityinc/last-compilation-buffer
          ad-do-it)
      ad-do-it)))

(defadvice shell-command-on-region
    (after sanityinc/shell-command-in-view-mode
           (start end command &optional output-buffer &rest other-args)
           activate)
  "Put "*Shell Command Output*" buffers into view-mode."
  (unless output-buffer
    (with-current-buffer "*Shell Command Output*"
      (view-mode 1))))


(after-load 'compile
  (require 'ansi-color)
  (defun sanityinc/colourise-compilation-buffer ()
    (when (eq major-mode 'compilation-mode)
      (ansi-color-apply-on-region compilation-filter-start (point-max))))
  (add-hook 'compilation-filter-hook 'sanityinc/colourise-compilation-buffer))

;; Key bindings
(global-set-key [S-f6] 'recompile)
(global-set-key [f6] 'compile)


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

Lenguajes derivados de C

En Emacs CC-Mode, gestiona los buffers escritos en C. Además, muchos modos para lenguajes parecidos a C (C++, PHP, Javascript, Java, y más) heredan partes de este modo, por lo que es uno de los esenciales.

init-cmode.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
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
(require 'compile)

;; C Compilation
(add-hook 'c-mode-hook
      (lambda ()
        (unless (file-exists-p "Makefile")
          (set (make-local-variable 'compile-command)
           ;; emulate make's .c.o implicit pattern rule, but with
           ;; different defaults for the CC, CPPFLAGS, and CFLAGS
           ;; variables:
           ;; $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
           (let ((file (file-name-nondirectory buffer-file-name)))
             (format "%s -c -o %s.o %s %s %s"
                 (or (getenv "CC") "gcc")
                 (file-name-sans-extension file)
                 (or (getenv "CPPFLAGS") "-DDEBUG=9")
                 (or (getenv "CFLAGS") "-ansi -pedantic -Wall -g")
                 file))))))

(add-hook 'c++-mode-hook
      (lambda ()
        (unless (file-exists-p "Makefile")
          (set (make-local-variable 'compile-command)
           ;; emulate make's .c.o implicit pattern rule, but with
           ;; different defaults for the CC, CPPFLAGS, and CFLAGS
           ;; variables:
           ;; $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $<
           (let ((file (file-name-nondirectory buffer-file-name)))
             (format "%s -c -o %s.o %s %s %s"
                 (or (getenv "CXX") "g++")
                 (file-name-sans-extension file)
                 (or (getenv "CPPFLAGS") "-DDEBUG=9")
                 (or (getenv "CFLAGS") "-ansi -pedantic -Wall -g")
                 file))))))

;; Use C++ Mode if a File starts with // or #include
(add-to-list 'magic-fallback-mode-alist '("^// " . c++-mode))
(add-to-list 'magic-fallback-mode-alist '("^#include" . c++-mode))

;;----------------------------------------------------------------------------
;; General for C-like languages
;;----------------------------------------------------------------------------

;; Remove system recursive search (it's veeeeeeeeeery slow)
(if (featurep 'semantic)
    (setq-mode-local c-mode
             semanticdb-find-default-throttle
             '(file project local unloaded recursive)))

(setq-default c-basic-offset 2)
(setq-default tab-width 2)
(setq-default indent-tabs-mode 't)

(defun my/c-mode-hook ()
  (require 'auto-complete-c-headers)
    (setq achead:include-directories
                (append '("/usr/lib/gcc/x86_64-linux-gnu/5/include"
                                    "/usr/local/include"
                                    "/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed"
                                    "/usr/include/x86_64-linux-gnu"
                                    "/usr/include")
                                achead:include-directories))
    (global-set-key [(shift return)] 'c-indent-new-comment-line)
    (add-to-list 'ac-sources 'ac-source-semantic2)
    (add-to-list 'ac-sources 'ac-source-c-headers)

    ;; Sets configuration for current file
    (setq c-basic-offset 2)
    (setq tab-width 2)
    (setq indent-tabs-mode 't)

    ;; Indentation correct
    ;; (c-set-offset 'arglist-cont-nonempty 'tab-width)
    ;; (c-set-offset 'arglist-cont-nonempty tab-width)
    (c-set-offset 'arglist-intro 't)
    (c-set-offset 'arglist-close 0)
    (local-set-key "\C-ch" 'eassist-switch-h-cpp)
    (local-set-key "\C-ce" 'eassist-list-methods)
  ;; References of function
  (local-set-key "\C-c\C-r" 'semantic-symref)

  )
(defun my/cpp-mode-hook ()
    (my/c-mode-hook)
    (setq achead:include-directories
                (append '("/usr/include/c++/5"
                                     "/usr/include/x86_64-linux-gnu/c++/5"
                                     "/usr/include/c++/5/backward")
                                achead:include-directories))
    )

(add-hook 'c++-mode-hook 'my/cpp-mode-hook)
(add-hook 'c-mode-hook 'my/c-mode-hook)

;; Derived from Alex Ott work
(defun my/ac-semantic-candidates ()
  (let* ((a (semantic-analyze-current-context ac-point))
         (tags (semantic-analyze-possible-completions a)))
    (cl-loop for tag in tags
             for class = (semantic-tag-class tag)
             for name = (semantic-format-tag-name tag nil nil)
             for type = (when (member class '(function variable type))
                          (semantic-format-tag-type tag nil))
             for args = (when (member class '(function type))
                          (semantic--format-tag-arguments
                           (if (eq class 'function)
                               (semantic-tag-function-arguments tag)
                             (list ""))
                           #'semantic-format-tag-prototype
                           nil))
                         for documentt = (semantic-documentation-for-tag tag)
                         for document = (if documentt documentt "No documentation found.")

             for summary = (if (eq class 'function)
                               (format "(%s) : %s\n\n ------------ \n%s" args type document)
                             (format "Ret: %s %s\n\n ------------ \n%s" class type document))

             collect
             (popup-make-item name :summary (symbol-name class) :document summary)

                         )))


(ac-define-source semantic2
  '((available . (require 'semantic/ia nil t))
    (candidates . my/ac-semantic-candidates)
    (prefix . cc-member)
        (symbol . "f")
    (requires . 0)))

(add-hook 'c++-mode-hook (lambda () (setq comment-start "/* "
                      comment-end   "*/")))

(add-hook 'c-mode-hook (lambda () (setq comment-start "/* "
                    comment-end   "*/")))

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

Lo primero que configuramos es la compilación. Permitiendo compilar un programa rápidamente utilizando el comando gcc o g++, en modo depuración, lo cual es muy útil para hacer compilaciones rápidas. También se utiliza el magic-fallback-mode-alist para que los archivos que comiencen por dos barras (//) o #include automáticamente utilicen el modo C++ sea cual sea su extensión. Esto es interesante, cuando estoy editando archivos de Arduino, por ejemplo.

En C-mode podemos configurar casi cualquier aspecto acerca de la colocación del código y de cómo lo indentamos. En principio podemos configurar modos de indentación predefinidos con:

1
(setq c-default-style "linux")

Donde en lugar de linux, podemos escribir gnu, bsd, k&r, stroustrup, y algunos más. Si queremos ver el listado completo, basta con hacer M-x (print c-style-alist). Aunque también podemos configurar cada uno de los elementos por separado, como es mi caso. Aunque hay más elementos para configurar, me basta con indent-tabs-mode, tab-width y c-basic-offset.

Ahora, lo más interesante para mí es el auto-completado. Para ello utilizo autocomplete y semantic. En este caso, para que la información salga mejor en semantic utilizo una función para generar el autocompletado. Es cierto que hay varias formas más de generarlo, mucho más rápidas que tirar de Elisp, pero no funciona excesivamente lento (excepto cuando hay muchos archivos en el proyecto para analizar).

init-php.el

En este archivo trataremos la configuración específica para PHP:

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
(require-package 'php-mode)

(when (maybe-require-package 'php-mode)
  (maybe-require-package 'smarty-mode))

;; From EmacsWiki: https://www.emacswiki.org/emacs/PhpMode
(defun my/php-symbol-lookup ()
  (interactive)
  (let ((symbol (symbol-at-point)))
    (if (not symbol)
        (message "No symbol at point.")

      (browse-url (concat "http://php.net/manual-lookup.php?pattern="
                          (symbol-name symbol))))))


(defun my/php-function-lookup ()
  (interactive)
  (let* ((function (symbol-name (or (symbol-at-point)
                                    (error "No function at point."))))
         (buf (url-retrieve-synchronously (concat "http://php.net/manual-lookup.php?pattern=" function))))
    (with-current-buffer buf
      (goto-char (point-min))
        (let (desc)
          (when (re-search-forward "<div class="methodsynopsis dc-description">\\(\\(.\\|\n\\)*?\\)</div>" nil t)
            (setq desc
              (replace-regexp-in-string
                " +" " "
                (replace-regexp-in-string
                  "\n" ""
                  (replace-regexp-in-string "<.*?>" "" (match-string-no-properties 1)))))

            (when (re-search-forward "<p class="para rdfs-comment">\\(\\(.\\|\n\\)*?\\)</p>" nil t)
              (setq desc
                    (concat desc "\n\n"
                            (replace-regexp-in-string
                             " +" " "
                             (replace-regexp-in-string
                              "\n" ""
                              (replace-regexp-in-string "<.*?>" "" (match-string-no-properties 1))))))))

          (if desc
              (message desc)
            (message "Could not extract function info. Press C-F1 to go the description."))))
    (kill-buffer buf)))

(require-package 'ac-php)

(add-hook 'php-mode-hook 'my/php-mode-stuff)

(defun my/php-mode-stuff ()
  (local-set-key (kbd "<f1>") 'my/php-function-lookup)
  (local-set-key (kbd "C-<f1>") 'my/php-symbol-lookup)
    ;; New versions of PHP have this :)
    (php-enable-psr2-coding-style)
    (fci-mode 0)
    (auto-complete-mode t)
    (require 'ac-php)
    (setq ac-sources  '(ac-source-dictionary ac-source-abbrev ac-source-php ) )
    (ac-php-core-eldoc-setup ) ;enable eldoc
    (define-key php-mode-map  (kbd "C-]") 'ac-php-find-symbol-at-point)   ;goto define
    (define-key php-mode-map  (kbd "C-t") 'ac-php-location-stack-back   ) ;go back
    )

(add-hook 'php-mode-hook 'my/php-mode-stuff)

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

En este fichero se definirán dos funciones para consultar ayuda en línea: my/php-function-lookup y my/php-symbol-lookup. Además, estableceremos el estilo de codificación psr2 y algunas teclas rápidas que vemos al final del post.

init-python.el

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
;;----------------------------------------------------------------------------
;; Python Mode
;;----------------------------------------------------------------------------
(require-package 'jedi)
(setq auto-mode-alist
      (append '(("SConstruct\'" . python-mode)
        ("SConscript\'" . python-mode))
              auto-mode-alist))

(require-package 'pip-requirements)
(defun my/python-mode-stuff ()
    ;; Jedi makes everything a lot easier for everybody!
    (jedi:setup)
    (define-key python-mode-map (kbd "C-]") 'jedi:goto-definition)   ;goto define
  (local-set-key (kbd "<f1>") 'jedi:show-doc)
    (setq jedi:complete-on-dot t)                 ; optional
    )
(add-hook 'python-mode-hook 'my/python-mode-stuff)

(myemacs/elapsed-time)

(provide 'init-python)

Mi configuración para Python es reducida, aunque podemos hacer muchas cosas nada más activando el modo jedi para Python. Actúa sobre el auto-completado, aunque tiene algunas utilidades de análisis de código que harán nuestra programación más amena y productiva.

init-javascript.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
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
(require-package 'json-mode)
(require-package 'js2-mode)
(require-package 'coffee-mode)

(defcustom preferred-javascript-mode
  (first (remove-if-not #'fboundp '(js2-mode js-mode)))
  "Javascript mode to use for .js files."
  :type 'symbol
  :group 'programming
  :options '(js2-mode js3-mode js-mode))

(defconst preferred-javascript-indent-level 2)

;; Need to first remove from list if present, since elpa adds entries too, which
;; may be in an arbitrary order
(eval-when-compile (require 'cl))
(setq auto-mode-alist (cons `("\\.\\(js\\|es6\\)\\(\\.erb\\)?\'" . ,preferred-javascript-mode)
                            (loop for entry in auto-mode-alist
                                  unless (eq preferred-javascript-mode (cdr entry))
                                  collect entry)))


(add-auto-mode 'js-mode "\\.json\'")

;; js2-mode

;; Change some defaults: customize them to override
(setq-default js2-basic-offset preferred-javascript-indent-level
                            js2-use-font-lock-faces t
                            js2-indent-on-enter-key t
                            js-auto-indent-p t
              js2-bounce-indent-p nil)
(after-load 'js2-mode
  ;; Disable js2 mode's syntax error highlighting by default...
  (setq-default js2-mode-show-parse-errors nil
                js2-mode-show-strict-warnings nil)
  ;; ... but enable it if flycheck can't handle javascript
  ;(autoload 'flycheck-get-checker-for-buffer "flycheck")
  (defun sanityinc/disable-js2-checks-if-flycheck-active ()
    (unless (flycheck-get-checker-for-buffer)
      (set (make-local-variable 'js2-mode-show-parse-errors) t)
      (set (make-local-variable 'js2-mode-show-strict-warnings) t)))
  (add-hook 'js2-mode-hook 'sanityinc/disable-js2-checks-if-flycheck-active)

  (add-hook 'js2-mode-hook (lambda () (setq mode-name "JS2")))

  (after-load 'js2-mode
    (js2-imenu-extras-setup)))

;; js3-mode
(add-hook 'js3-mode-hook '(lambda () (setq mode-name "JS3")))
(setq js3-auto-indent-p t
      js3-enter-indents-newline t
      js3-indent-on-enter-key t
            js3-indent-level preferred-javascript-indent-level)

;; js-mode
(setq-default js-indent-level preferred-javascript-indent-level)

(add-to-list 'interpreter-mode-alist (cons "node" preferred-javascript-mode))

;; Javascript nests {} and () a lot, so I find this helpful

(when (and (executable-find "ag")
           (maybe-require-package 'xref-js2))
  (after-load 'js2-mode
    (define-key js2-mode-map (kbd "M-.") nil)
    (add-hook 'js2-mode-hook
              (lambda () (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t)))))

;;; Coffeescript

(after-load 'coffee-mode
  (setq coffee-js-mode preferred-javascript-mode
        coffee-tab-width preferred-javascript-indent-level))

(when (fboundp 'coffee-mode)
  (add-to-list 'auto-mode-alist '("\\.coffee\\.erb\'" . coffee-mode)))

;; standard javascript-mode
(setq javascript-indent-level preferred-javascript-indent-level)

(add-to-list 'interpreter-mode-alist (cons "nodejs" preferred-javascript-mode))

;; ---------------------------------------------------------------------------
;; Run and interact with an inferior JS via js-comint.el
;; ---------------------------------------------------------------------------
;; ---------------------------------------------------------------------------
;; Run and interact with an inferior JS via js-comint.el
;; ---------------------------------------------------------------------------

(setq inferior-js-program-command "nodejs")

(defvar inferior-js-minor-mode-map (make-sparse-keymap))
;; (define-key inferior-js-minor-mode-map "\C-x\C-e" 'js-send-last-sexp)
;; (define-key inferior-js-minor-mode-map "\C-\M-x" 'js-send-last-sexp-and-go)
;; (define-key inferior-js-minor-mode-map "\C-cb" 'js-send-buffer)
;; (define-key inferior-js-minor-mode-map "\C-c\C-b" 'js-send-buffer-and-go)
;; (define-key inferior-js-minor-mode-map "\C-cl" 'js-load-file-and-go)

(define-minor-mode inferior-js-keys-mode
  "Bindings for communicating with an inferior js interpreter."
  nil " InfJS" inferior-js-minor-mode-map)

(dolist (hook '(js2-mode-hook js3-mode-hook js-mode-hook))
    (add-hook hook 'inferior-js-keys-mode))

;; ---------------------------------------------------------------------------
;; Alternatively, use skewer-mode
;; ---------------------------------------------------------------------------

(when (maybe-require-package 'skewer-mode)
  (after-load 'skewer-mode
    (add-hook 'skewer-mode-hook
              (lambda () (inferior-js-keys-mode -1)))))


(provide 'init-javascript)

Con este fichero configuramos tanto Javascript, ficheros Json y Coffeescript. Hay algunas teclas comentadas porque realmente no las utilizo, pero podríamos utilizar js-comint-mode para ejecutar código javascript en un buffer mientras editamos en otro.

nxml-mode.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
; From https://github.com/purcell/emacs.d/blob/master/lisp/init-nxml.el
(add-auto-mode
 'nxml-mode
 (concat "\\."
         (regexp-opt
          '("xml" "xsd" "sch" "rng" "xslt" "svg" "rss"
            "gpx" "tcx" "plist"))
         "\'"))
(setq magic-mode-alist (cons '("<\\?xml " . nxml-mode) magic-mode-alist))
(fset 'xml-mode 'nxml-mode)
(add-hook 'nxml-mode-hook (lambda ()
                            (set (make-local-variable 'ido-use-filename-at-point) nil)
                                                        (setq nxml-slash-auto-complete-flag t)
                                                        (auto-complete-mode t)
                                                        (local-set-key (kbd "RET") 'newline-and-indent)))


;; See: http://sinewalker.wordpress.com/2008/06/26/pretty-printing-xml-with-emacs-nxml-mode/
(defun sanityinc/pp-xml-region (beg end)
  "Pretty format XML markup in region. The function inserts
linebreaks to separate tags that have nothing but whitespace
between them.  It then indents the markup by using nxml's
indentation rules."

  (interactive "r")
  (unless (use-region-p)
    (setq beg (point-min)
          end (point-max)))
  ;; Use markers because our changes will move END
  (setq beg (set-marker (make-marker) begin)
        end (set-marker (make-marker) end))
  (save-excursion
    (goto-char beg)
    (while (search-forward-regexp "\>[ \\t]*\<" end t)
      (backward-char) (insert "\n"))
    (nxml-mode)
    (indent-region begin end)))

;;----------------------------------------------------------------------------
;; Integration with tidy for html + xml
;;----------------------------------------------------------------------------
(require-package 'tidy)
(add-hook 'nxml-mode-hook (lambda () (tidy-build-menu nxml-mode-map)))

(defun sanityinc/tidy-buffer-xml (beg end)
  "Run "tidy -xml" on the region from BEG to END, or whole buffer."
  (interactive "r")
  (unless (use-region-p)
    (setq beg (point-min)
          end (point-max)))
  (shell-command-on-region beg end "tidy -xml -q -i" (current-buffer) t "*tidy-errors*" t))

(defun jta/reformat-xml ()
  "Reformats xml to make it readable (respects current selection)."
  (interactive)
  (save-excursion
    (let ((beg (point-min))
          (end (point-max)))
      (if (and mark-active transient-mark-mode)
          (progn
            (setq beg (min (point) (mark)))
            (setq end (max (point) (mark))))
        (widen))
      (setq end (copy-marker end t))
      (goto-char beg)
      (while (re-search-forward ">\\s-*<" end t)
        (replace-match ">\n<" t t))
      (goto-char beg)
      (indent-region beg end nil))))


(provide 'init-nxml)

Ahora le toca el turno a los lenguajes XML y derivados. En los que, cuando los editamos podemos tener algunas ventajas, como por ejemplo, ponerlos bonitos. Aunque hay tres funciones para ello, sanityinc/pp-xml-region, sanityinc/tidy-buffer-xml y jta/reformat-xml cada una tiene sus pros y sus contras. Aunque la única que no me ha dejado tirado nunca es jta/reformat-xml aunque puede llegar a ser algo lenta.

init-ruby.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
; From https://github.com/purcell/emacs.d/blob/master/lisp/init-ruby-mode.el
;;; Basic ruby setup
(require-package 'ruby-mode)
(require-package 'ruby-hash-syntax)

(add-auto-mode 'ruby-mode
               "Rakefile\'" "\\.rake\'" "\\.rxml\'"
               "\\.rjs\'" "\\.irbrc\'" "\\.pryrc\'" "\\.builder\'" "\\.ru\'"
               "\\.gemspec\'" "Gemfile\'" "Kirkfile\'")
(add-auto-mode 'conf-mode "Gemfile\\.lock\'")

(setq ruby-use-encoding-map nil)

(after-load 'ruby-mode
  (define-key ruby-mode-map (kbd "TAB") 'indent-for-tab-command)

  ;; Stupidly the non-bundled ruby-mode isn't a derived mode of
  ;; prog-mode: we run the latter's hooks anyway in that case.
  (add-hook 'ruby-mode-hook
            (lambda ()
              (unless (derived-mode-p 'prog-mode)
                (run-hooks 'prog-mode-hook)))))

(add-hook 'ruby-mode-hook 'subword-mode)

(after-load 'page-break-lines
  (push 'ruby-mode page-break-lines-modes))

(require-package 'rspec-mode)


;;; Inferior ruby
(require-package 'inf-ruby)



;;; Ruby compilation
(require-package 'ruby-compilation)

(after-load 'ruby-mode
  (let ((m ruby-mode-map))
    (define-key m [S-f7] 'ruby-compilation-this-buffer)
    (define-key m [f7] 'ruby-compilation-this-test)))

(after-load 'ruby-compilation
  (defalias 'rake 'ruby-compilation-rake))



;;; Robe
(require-package 'robe)
(after-load 'ruby-mode
  (add-hook 'ruby-mode-hook 'robe-mode))
(after-load 'company
  (dolist (hook '(ruby-mode-hook inf-ruby-mode-hook html-erb-mode-hook haml-mode))
    (add-hook hook
              (lambda () (sanityinc/local-push-company-backend 'company-robe)))))



;; Customise highlight-symbol to not highlight do/end/class/def etc.
(defun sanityinc/suppress-ruby-mode-keyword-highlights ()
  "Suppress highlight-symbol for do/end etc."
  (set (make-local-variable 'highlight-symbol-ignore-list)
       (list (concat "\\_<" (regexp-opt '("do" "end")) "\\_>"))))
(add-hook 'ruby-mode-hook 'sanityinc/suppress-ruby-mode-keyword-highlights)

Aunque no soy muy de Ruby, alguna vez he tenido que editar algún código y esta configuración no me ha ido mal.

init-sql.el

Del mismo modo que antes, incluyo init-sql.el para trabajar con archivos SQL:

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
; From https://github.com/purcell/emacs.d/blob/master/lisp/init-sql.el
(require-package 'sql-indent)
(after-load 'sql
  (require 'sql-indent))

(after-load 'sql
  ;; sql-mode pretty much requires your psql to be uncustomised from stock settings
  (push "--no-psqlrc" sql-postgres-options))

(defun sanityinc/pop-to-sqli-buffer ()
  "Switch to the corresponding sqli buffer."
  (interactive)
  (if sql-buffer
      (progn
        (pop-to-buffer sql-buffer)
        (goto-char (point-max)))
    (sql-set-sqli-buffer)
    (when sql-buffer
      (sanityinc/pop-to-sqli-buffer))))

(after-load 'sql
  (define-key sql-mode-map (kbd "C-c C-z") 'sanityinc/pop-to-sqli-buffer)
  (when (package-installed-p 'dash-at-point)
    (defun sanityinc/maybe-set-dash-db-docset ()
      (when (eq sql-product 'postgres)
        (set (make-local-variable 'dash-at-point-docset) "psql")))

    (add-hook 'sql-mode-hook 'sanityinc/maybe-set-dash-db-docset)
    (add-hook 'sql-interactive-mode-hook 'sanityinc/maybe-set-dash-db-docset)
    (defadvice sql-set-product (after set-dash-docset activate)
      (sanityinc/maybe-set-dash-db-docset))))

(setq-default sql-input-ring-file-name
              (expand-file-name ".sqli_history" user-emacs-directory))

;; See my answer to https://emacs.stackexchange.com/questions/657/why-do-sql-mode-and-sql-interactive-mode-not-highlight-strings-the-same-way/673
(defun sanityinc/font-lock-everything-in-sql-interactive-mode ()
  (unless (eq 'oracle sql-product)
    (sql-product-font-lock nil nil)))
(add-hook 'sql-interactive-mode-hook 'sanityinc/font-lock-everything-in-sql-interactive-mode)


(after-load 'page-break-lines
  (push 'sql-mode page-break-lines-modes))

(provide 'init-sql)

Otros lenguajes init-langs.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
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
;;----------------------------------------------------------------------------
;; General for all languages
;;----------------------------------------------------------------------------
;; Useful for editing compressed files transparently
(auto-compression-mode t)

; From https://github.com/purcell/emacs.d/blob/master/lisp/init-markdown.el
;;----------------------------------------------------------------------------
;; Markdown mode
;;----------------------------------------------------------------------------
(when (maybe-require-package 'markdown-mode)
  (after-load 'whitespace-cleanup-mode
    (push 'markdown-mode whitespace-cleanup-mode-ignore-modes)))

;;----------------------------------------------------------------------------
;; CSV Mode
;;----------------------------------------------------------------------------

(require-package 'csv-mode)
(require-package 'csv-nav)

(add-auto-mode 'csv-mode "\\.[Cc][Ss][Vv]\'")

(setq csv-separators '("," ";" "|" " "))

;;----------------------------------------------------------------------------
;; HTML Mode
;;----------------------------------------------------------------------------
(require-package 'tidy)
(add-hook 'html-mode-hook (lambda () (tidy-build-menu html-mode-map)))

(require-package 'tagedit)
(after-load 'sgml-mode
  (tagedit-add-paredit-like-keybindings)
  (add-hook 'sgml-mode-hook (lambda () (tagedit-mode 1))))

(add-auto-mode 'html-mode "\\.\\(jsp\\|tmpl\\)\'")

;;----------------------------------------------------------------------------
;; CSS Mode
;;----------------------------------------------------------------------------
(setq-default cssm-indent-level 4)
(setq-default cssm-newline-before-closing-bracket t)
(setq-default cssm-indent-function #'cssm-c-style-indenter)
;; (setq-default scss-sass-command '/usr/local/bin/sass)
(setq-default cssm-mirror-mode nil)

;;----------------------------------------------------------------------------
;; Web mode
;;----------------------------------------------------------------------------
(require-package 'web-mode)
(add-hook 'web-mode-hook (lambda () ((fci-mode 0))))

(add-to-list 'auto-mode-alist '("\\.phtml\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.[agj]sp\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mustache\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.djhtml\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?\'" . web-mode))

;;----------------------------------------------------------------------------
;; Multiple major modes
;;----------------------------------------------------------------------------
(require-package 'mmm-mode)
(require 'mmm-auto)
(setq mmm-global-mode 'buffers-with-submode-classes)
(setq mmm-submode-decoration-level 2)

;;----------------------------------------------------------------------------
;; Some more mode languages
;;----------------------------------------------------------------------------
(require-package 'gnuplot)
(require-package 'lua-mode)
(require-package 'ansible)
(require-package 'elf-mode)

(provide 'init-langs)

Aquí vemos cómo se comportará Emacs con archivos HTML, XML, lua, scripts para ansible, gnuplot, Markdown y algunos más. Eso sí, una cosa que me encanta, auto-compression-mode, que es capaz de utilizar archivos comprimidos de forma transparente para nosotros. Emacs se encarga de comprimir y descomprimir cuando lo crea necesario.

Teclas rápidas

En este post he añadido algunas combinaciones de teclas más a mi Emacs, aquí tenemos un resumen:

  • F6: Compilar el código actual.
  • Shift+F6: Recompilar el código actual. Útil para utilizar una ventana de compilación previamente abierta.
  • C-c h (en C): Cambia entre el buffer con el encabezado y las implementaciones.
  • C-c e (en C): Lista los métodos de un archivos.
  • C-c C-r (en C): Busca referencias a una etiqueta (función, variable, clase, tipo…) dentro de
    un buffer.
  • F1 (en PHP): Muestra ayuda del manual sobre una función del lenguaje. La busca en php.net y visualiza las primeras líneas.
  • F1 (en Python): Muestra ayuda del manual sobre una función o cualquier símbolo
    del lenguaje.
  • C-F1 (en PHP): Se dirige a la ayuda en Internet a través del navegador.
  • C-] (en PHP y Python): Mueve el cursor hacia la definición de la función. Cuando ésta está en el mismo buffer.
  • C-t (en PHP): Vuelve donde estábamos antes. Si por ejemplo, nos hemos movido hacia la definición de función.

Más modos y configuraciones

Seguro que existen muchísimos modos de Emacs más para programar. Me gustaría saber si utilizas alguno que te haya salvado la vida, o funcione realmente bien para los lenguajes con los que trabajas a diario.

Foto principal: unsplash-logoJoão Silas

También podría interesarte....

There are 15 comments left Ir a comentario

  1. Pingback: Creando una configuración personalizada para Emacs. Mi .emacs.d con explicaciones detalladas (III – Lenguajes de programación) | PlanetaLibre /

  2. Pearland Concrete Contractors /
    Usando Google Chrome Google Chrome 116.0.0.0 en Windows Windows NT

    It’s great to see how you’ve tailored Emacs to support various programming languages efficiently.

  3. timothyferriss /
    Usando Google Chrome Google Chrome 117.0.0.0 en Windows Windows NT

    ¡Suena genial que estés compartiendo tu configuración personalizada de Emacs! Configurar Emacs para admitir 2048 varios lenguajes de programación puede ser una tarea desafiante, pero puede hacer que tu flujo de trabajo sea mucho más eficiente.

  4. Baltimore mud and tape /
    Usando Google Chrome Google Chrome 117.0.0.0 en Windows Windows NT

    Having dedicated configurations for each language can greatly enhance your workflow.

  5. 토토사이트 /
    Usando Google Chrome Google Chrome 118.0.0.0 en Windows Windows NT

    I have added your blog to my bookmark. I will read your article more frequently!토토사이트

  6. personalizada /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    En esta tercera entrega de la serie sobre mi configuración personalizada para Emacs, nos sumergiremos en el fascinante mundo de los lenguajes de programación. En mi día a día, trabajo principalmente con C, C++, PHP, Python y Bash, aunque también me aseguro de tener un soporte adecuado para Emacs Lisp y otros lenguajes que ocasionalmente utilizo. suika game

  7. 먹튀검증 /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    A very awesome blog post. We are really grateful for your blog post. You will find a lot of approaches after visiting your post먹튀검증

  8. jeffreestar /
    Usando Google Chrome Google Chrome 119.0.0.0 en Windows Windows NT

    This configuration provides a good starting backpack battles point for Emacs users who work with various programming languages. You can customize it further to suit your specific needs and preferences.

  9. fnf /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Your articles have helped me to learn a lot of interesting information on this topic and they are important material from which I can come up with many good ideas.

  10. Bridgeport /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Great to see your detailed Emacs configuration series! The focus on programming languages is particularly interesting.

  11. mailisa /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Your detailed explanation of the Emacs configuration for programming languages is incredibly helpful. The breakdown of each Buckshot Roulette section makes it easier for beginners like me to understand and customize.

  12. jeffreestar /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    ¡Excelente! Parece que estás trabajando en crear una configuración personalizada para Emacs centrada en el soporte de Spend Elon Musk Money diversos lenguajes de programación.

  13. orabelle hana /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    The programming language is quite confusing flagle

  14. marga /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Trends in hairstyles can vary widely depending on individual preferences, cultural influences, and global fashion trends. However, here are some hairstyles that could be trending for Indian men in 2024:Ultimately, the best hairstyle for you depends on your personal style, face shape, hair texture, and lifestyle. Consider consulting with a professional hairstylist who can recommend the most suitable hairstyle based on your individual characteristics and preferences.https://www.wpgio.com/best-trending-hairstyles-for-indian-men/

  15. JASON /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Thank you so much for your kind words! I’m delighted that you enjoy the content and find it magical. Creating content that brings joy to readers like you is truly rewarding, and I appreciate your feedback.

    I’m always eager to hear suggestions for topics or themes you’d like to see more of. Whether it’s specific areas of interest, new trends, or anything else you’d like to explore, please feel free to share your ideas. Your input helps us tailor the content to better suit your interests and preferences.
    When choosing a company for armed security guard services in New York, it’s essential to consider factors such as experience, reputation, licensing, and the ability to meet specific security requirements. Additionally, inquire about the training and qualifications of the armed security personnel provided by the company to ensure they meet your needs.NYC Security Guard

Leave a Reply to Anónimo Cancle Reply