¿Cómo puedo obtener una regla en la columna 80?


81

Como programador, quiero ver una regla en una columna específica (generalmente 80), así que veo cuándo cruzo esa columna, pero también para ver qué tan cerca me estoy acercando para poder formatear mi código temprano.

Las opciones que he encontrado hasta ahora no logran este objetivo:

  • whitespace-mode, column-enforce-modey column-markersolo resalta filas individuales después de que el texto en la fila ya haya pasado el fill-column. Me gustaría ver cuándo me estoy acercando a la columna, no solo cuando la cruce.
  • fill-column-indicatorsería una buena solución, salvo que se rompe auto-complete-mode, company-mode, avy, y mucho más. Estos son problemas que parecen difíciles de solucionar, cada uno de los cuales requiere una solución individual; por ejemplo, vea el company-modeproblema y el auto-complete-modeproblema , el último tiene más de dos años).

¿Hay alguna alternativa mejor?


8
Esta no es una respuesta a su pregunta per se, pero una solución práctica es establecer el ancho de su ventana / marco en 80 caracteres.
Eric Brown

Gracias por la sugerencia. Creo que preferiría tener el ancho opcional disponible cuando sea necesario, pero ciertamente es una opción. :-)
Jorgen Schäfer

55
Agregaría a la sugerencia de @ EricBrown, no cambie el ancho real de la ventana, sino que establezca el margen derecho de la ventana para que el espacio de edición sea de 80 caracteres. (set-window-margins nil 0 (max (- (window-width) 80) 0))Entonces, si tiene una ventana de 120 caracteres de ancho, reducirá el espacio que tiene para mostrar el código a 80 caracteres. De esta manera, no estropeará la configuración de su ventana y puede desactivarla si lo desea. Si tiene flecos, en realidad habrá una línea dibujada en 80 columnas.
Jordon Biondo

1
Aquí hay una idea general de la idea: gist.github.com/jordonbiondo/aa6d68b680abdb1a5f70 y aquí está en acción: i.imgur.com/dUx4bNz.gif
Jordon Biondo

@ jordon-biondo: esto no incluye los
ideasman42

Respuestas:


39

fill-column-indicatores la solución más madura, y si encuentra código basado en superposición con el que entra en conflicto, puede agregar código para suspender fci-modemientras el código conflictivo está activo. Por ejemplo, el siguiente código hace que funcione con auto-complete:

  (defun sanityinc/fci-enabled-p () (symbol-value 'fci-mode))

  (defvar sanityinc/fci-mode-suppressed nil)
  (make-variable-buffer-local 'sanityinc/fci-mode-suppressed)

  (defadvice popup-create (before suppress-fci-mode activate)
    "Suspend fci-mode while popups are visible"
    (let ((fci-enabled (sanityinc/fci-enabled-p)))
      (when fci-enabled
        (setq sanityinc/fci-mode-suppressed fci-enabled)
        (turn-off-fci-mode))))

  (defadvice popup-delete (after restore-fci-mode activate)
    "Restore fci-mode when all popups have closed"
    (when (and sanityinc/fci-mode-suppressed
               (null popup-instances))
      (setq sanityinc/fci-mode-suppressed nil)
      (turn-on-fci-mode)))

55
O visite github.com/company-mode/company-mode/issues/… para obtener una solución similar company-mode.
Dmitry

Hola, gracias por compartir la idea. ¿Cómo hago para que esto funcione? Tengo el código en mi .emacs, pero supongo que tengo que agregar algunos ganchos para que funcione.
PierreE

Sí, el ejemplo anterior aconseja popup-createy popup-delete, dependiendo de su caso de uso, es posible que necesite asesorar diferentes funciones.
sanityinc


21

Aquí hay una opción que es más robusta, no rompe casi nada (ocasionalmente, el modo de empresa es una excepción notable), pero no es tan conveniente como fill-column-indicator.

Utilice el formato de línea de encabezado para marcar la columna 80 en el encabezado.
Algo como lo siguiente debería ser suficiente:

(setq-default header-line-format 
              (list " " (make-string 79 ?-) "|"))

Debe cambiar el número de espacios en esa primera cadena dependiendo del tamaño de su franja izquierda. Pero aparte de eso, esto debería funcionar razonablemente bien. No es tan conveniente como una regla en el búfer real, pero ayuda.

También puede configurarlo para que se aplique solo en buffers de programación.

(defun prog-mode-header-line ()
  "Setup the `header-line-format' on for buffers."
  (setq header-line-format 
        (list " " (make-string 79 ?-) "|")))

(add-hook 'prog-mode-hook #'prog-mode-header-line)

Resultado:
debería obtener algo como lo siguiente (la primera línea no está realmente en el búfer, sino en el encabezado).

-------------------------------------------------------------------------------|
;; This is what your buffer should look like all the way up to column number 80.
(setq some-dummy-variable we-are-all-friends)

1
Tenga en cuenta que en Emacs 24.3 esto también romperá el modo de empresa, al menos en algunos casos extremos. Emacs 24.3 no tiene en cuenta correctamente la línea de encabezado al calcular la altura de una ventana. En consecuencia, la Compañía no puede dibujar ventanas emergentes adecuadas en casos donde la altura es importante, es decir, en la parte inferior del búfer.
lunaryorn

1
Esta es una idea realmente interesante. Lástima que no puedo marcar dos respuestas como correctas, la respuesta "patch fci" tiene algunos inconvenientes y, dependiendo de las circunstancias, esta puede ser una mejor opción. ¡Gracias!
Jorgen Schäfer

10
También hay M-x ruler-mode.
sanityinc

Esto no comienza después de los números (cuando se muestran los números de línea)
ideasman42

17

Después de mucho sufrimiento debido a la fill-column-indicatorintroducción de varios errores , lo eliminé de mi configuración para siempre.

Lo que uso actualmente es la funcionalidad integrada de Emacs para resaltar líneas que son demasiado largas. Esto incluso se ve mejor, no lo habilitaría fill-column-indicatorahora, incluso si estuviera libre de errores.

Para empezar, puedes tomar mi configuración:

(setq-default
 whitespace-line-column 80
 whitespace-style       '(face lines-tail))

Luego habilítelo donde desee. Lo uso solo en el contexto de programación:

(add-hook 'prog-mode-hook #'whitespace-mode)

9

¿Hay alguna alternativa mejor?

Emacs 27 admitirá un indicador de columna de relleno de forma nativa a través del modo menor local de búfer display-fill-column-indicator-modey su contraparte global global-display-fill-column-indicator-mode.

Aquí está en acción:

ingrese la descripción de la imagen aquí

quoth (emacs) Displaying Boundaries:

14.15 Displaying Boundaries
===========================

Emacs can add an indicator to display a fill column position.  The fill
column indicator is a useful functionality specially in prog-mode to
indicate the position of an specific column.

   You can set the buffer-local variables
‘display-fill-column-indicator’ and
‘display-fill-column-indicator-character’ to activate the indicator and
controls how the indicator looks.

   Alternatively you can type ‘M-x display-fill-column-indicator-mode’
or ‘M-x global-display-fill-column-indicator-mode’ which enables the
indicator locally and globally respectively and also chooses the
character to use if none is set already.  It is possible to use the
first one to activate the indicator in a hook or the second one to
enable it globally.

   There are 2 buffer local variables and 1 face to customize this mode:

‘display-fill-column-indicator-column’
     Specifies the column number where the indicator should be set.  It
     can take positive numerical values for the column or the special
     value ‘t’ which means that the variable ‘fill-column’ will be used.

     Any other value disables the indicator.  The default value is ‘t’.

‘display-fill-column-indicator-character’
     Specifies the character used for the indicator.  This character can
     be any valid char including unicode ones if the actual font
     supports them.

     When the mode is enabled through the functions
     ‘display-fill-column-indicator-mode’ or
     ‘global-display-fill-column-indicator-mode’, the initialization
     functions check if this variable is ‘non-nil’, otherwise the
     initialization tries to set it to U+2502 or ‘|’.

‘fill-column-indicator’
     Specifies the face used to display the indicator.  It inherits its
     default values from shadow but without background color.  To change
     the indicator color you need to set only the foreground color of
     this face.

7

Esta página de EmacsWiki tiene mucha información sobre diferentes formas de marcar una columna en particular o informarle cuando la pase.

El que uso es Mode Line Position .

Pero otros incluyen mostrando una línea vertical en la columna ( Columna marcador , fill-column Indicador ) y usando el modo de espacio en blanco para resaltar el texto que va más allá de la columna.

(Si necesita que la línea esté muy a la derecha de todo el texto en todas las filas, siempre puede activarla picture-mode, pero eso probablemente sea útil aquí solo como una solución temporal).

Vea también Buscar largas colas para encontrar formas de largas colas bajo demanda.


6

No es exactamente lo que quieres, pero una regla como @ Malabarba desperdiciará espacio, aquí hay una mejor solución:

Hay un paquete incorporado en emacs-goodies-el(recomiende instalarlo en la terminal) llamado highlight-beyond-fill-column.el , agregue esto a su .emacso init.el:

(setq-default fill-column 80)
(add-hook 'prog-mode-hook 'highlight-beyond-fill-column)
(custom-set-faces '(highlight-beyond-fill-column-face
                    ((t (:foreground "red" )))))

El texto más allá del fill-columncual está 80 en el fragmento se resaltará con el color de red. Puedes configurar la cara como quieras.


1

Como fill-column-indicatores bastante pesado, esta solución muestra un carácter a la derecha de la línea actual.

Entonces, cuando está escribiendo, puede ver el límite de línea antes de excederlo.

Esto define el modo menor hl-line-margin-mode:

;; Global, ensures one active margin for the active buffer.
(defvar hl-line-margin--overlay nil)

(defun hl-line-margin--overlay-clear ()
  "Clear the overlays."
  (when hl-line-margin--overlay
    (delete-overlay hl-line-margin--overlay)
    (setq hl-line-margin--overlay nil)))

(defun hl-line-margin--overlay ()
  "Create the line highlighting overlay."
  ;; Remove in the event of a changed buffer,
  ;; ensures we update for a modified fill-column.
  (when (and hl-line-margin--overlay
             (not (eq (current-buffer)
                      (overlay-buffer hl-line-margin--overlay))))
    (hl-line-margin--overlay-clear))
  (unless hl-line-margin--overlay
    (setq hl-line-margin--overlay (make-overlay 0 0))
    (let ((space `((space :align-to ,fill-column)
                   (space :width 0))))
      (overlay-put hl-line-margin--overlay 'after-string
                   (concat (propertize " " 'display space 'cursor t)
                           (propertize " " 'face '(:inverse-video t))))))
  (let ((eol (line-end-position)))
    (unless (eql eol (overlay-start hl-line-margin--overlay))
      (move-overlay hl-line-margin--overlay eol eol))))

(defun hl-line-margin-mode-enable ()
  "Turn on `hl-line-margin-mode' for the current buffer."
  (add-hook 'post-command-hook #'hl-line-margin--overlay nil t))

(defun hl-line-margin-mode-disable ()
  "Turn off `hl-line-margin-mode' for the current buffer."
  (hl-line-margin--overlay-clear)
  (remove-hook 'post-command-hook #'hl-line-margin--overlay t))

;;;###autoload
(define-minor-mode hl-line-margin-mode
  "Show a character at the fill column of the current line."
  :lighter ""
  (cond (hl-line-margin-mode
         (jit-lock-unregister #'hl-line-margin-mode-enable)
         (hl-line-margin-mode-enable))
        (t
         (jit-lock-unregister #'hl-line-margin-mode-disable)
         (hl-line-margin-mode-disable))))

Si usa evil-modey desea limitar esto al modo de inserción, puede agregar los siguientes ganchos:

(add-hook 'evil-insert-state-entry-hook #'hl-line-margin-mode-enable)
(add-hook 'evil-insert-state-exit-hook #'hl-line-margin-mode-disable)