Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

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

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:

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

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 "
">\\(\\(.\\|\n\\)*?\\)
"
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 "

">\\(\\(.\\|\n\\)*?\\)

"
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 "") 'my/php-function-lookup)
  (local-set-key (kbd "C-") '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 "") '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)

 


This post first appeared on Poesía Binaria - Programación, Tecnología Y Sof, please read the originial post: here

Share the post

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

×

Subscribe to Poesía Binaria - Programación, Tecnología Y Sof

Get updates delivered right to your inbox!

Thank you for your subscription

×