From: Eli Zaretskii Date: Sat, 12 Dec 2015 10:53:35 +0000 (+0200) Subject: Document multi-mode indentation facilities X-Git-Tag: emacs-25.0.90~492 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5cc4f33b4ad0de0024c11ec41bcefcab34493efb;p=emacs.git Document multi-mode indentation facilities * doc/lispref/text.texi (Mode-Specific Indent): Document 'prog-indentation-context', 'prog-first-column', and 'prog-widen'. * lisp/progmodes/prog-mode.el (prog-indentation-context) (prog-widen): Doc fixes. --- diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 4d26638a94c..f3679a88f74 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -2362,6 +2362,84 @@ already indented, it calls @code{completion-at-point} to complete the text at point (@pxref{Completion in Buffers}). @end defopt +@cindex literate programming +@cindex multi-mode indentation + Some major modes need to support embedded regions of text whose +syntax belongs to a different major mode. Examples include +@dfn{literate programming} source files that combine documentation and +snippets of source code, Yacc/Bison programs that include snippets of +plain C code, etc. To correctly indent the embedded chunks, the major +mode needs to delegate the indentation to another mode's indentation +engine (e.g., call @code{c-indent-defun} for C code or +@code{python-indent-line} for Python), while providing it with some +context to guide the indentation. The following facilities support +such multi-mode indentation. + +@defvar prog-indentation-context +This variable, when non-@code{nil}, holds the indentation context for +the sub-mode's indentation engine provided by the superior major mode. +The value should be a list of the form @code{(@var{first-column} +@w{(@var{start} . @var{end})} @code{prev-chunk})}. The members of the +list have the following meaning: + +@table @var +@item first-column +The column to be used for top-level constructs. This replaces the +default value of the top-level column used by the sub-mode, usually +zero. +@item start +@itemx end +The region of the code chunk to be indented by the sub-mode. The +value of @var{end} can be @code{nil}, which stands for the value of +@code{point-max}. +@item prev-chunk +If this is non-@code{nil}, it should provide the sub-mode's +indentation engine with a virtual context of the code chunk. Valid +values include: + +@itemize @minus +@item +A string whose contents is the text the sub-mode's indentation engine +should consider to precede the code chunk. The sub-mode's indentation +engine can add text properties to that string, to be reused in +repeated calls with the same string, thus using it as a cache. An +example where this is useful is code chunks that need to be indented +as function bodies, but lack the function's preamble---the string +could then include that missing preamble. +@item +A function. It is expected to be called with the start position of +the current chunk, and should return a cons cell +@w{@code{(@var{prev-start} . @var{prev-end})}} that specifies the +region of the previous code chunk, or @code{nil} if there is no previous +chunk. This is useful in literate-programming sources, where code is +split into chunks, and correct indentation needs to access previous +chunks. +@end itemize +@end table +@end defvar + +The following convenience functions should be used by major mode's +indentation engine in support of invocations as sub-modes of another +major mode. + +@defun prog-first-column +Call this function instead of using a literal value (usually, zero) of +the column number for indenting top-level program constructs. The +function's value is the column number to use for top-level constructs. +When no superior mode is in effect, this function returns zero. +@end defun + +@defun prog-widen +Call this function instead of @code{widen} to remove any restrictions +imposed by the mode's indentation engine and restore the restrictions +recorded in @code{prog-indentation-context}. This prevents the +indentation engine of a sub-mode from inadvertently operating on text +outside of the chunk it was supposed to indent, and preserves the +restriction imposed by the superior mode. When no superior mode is in +effect, this function just calls @code{widen}. +@end defun + + @node Region Indent @subsection Indenting an Entire Region diff --git a/etc/NEWS b/etc/NEWS index 01447cde163..246ee37a848 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -321,8 +321,17 @@ the ordering of object keys by default. `json-pretty-print-buffer-ordered' pretty prints JSON objects with object keys sorted alphabetically. ++++ ** Prog mode has some support for multi-mode indentation. -See `prog-indentation-context' and `prog-widen'. +This allows better indentation support in modes that support multiple +programming languages in the same buffer, like literate programming +environments or ANTLR programs with embedded Python code. + +A major mode can provide indentation context for a sub-mode through +the `prog-indentation-context' variable. To support this, modes that +provide indentation should use `prog-widen' instead of `widen' and +`prog-first-column' instead of a literal zero. See the node +"Mode-Specific Indent" in the ELisp manual for more details. ** Prettify Symbols mode diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index b459cbfd286..d05e6369b86 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -50,49 +50,51 @@ "Keymap used for programming modes.") (defvar prog-indentation-context nil - "Non-nil while indenting embedded code chunks. + "When non-nil, provides context for indenting embedded code chunks. + There are languages where part of the code is actually written in a sub language, e.g., a Yacc/Bison or ANTLR grammar also consists of plain C code. This variable enables the major mode of the -main language to use the indentation engine of the sub mode for -lines in code chunks written in the sub language. +main language to use the indentation engine of the sub-mode for +lines in code chunks written in the sub-mode's language. When a major mode of such a main language decides to delegate the indentation of a line/region to the indentation engine of the sub -mode, it is supposed to bind this variable to non-nil around the call. +mode, it should bind this variable to non-nil around the call. + +The non-nil value should be a list of the form: -The non-nil value looks as follows (FIRST-COLUMN (START . END) PREVIOUS-CHUNKS) -FIRST-COLUMN is the column the indentation engine of the sub mode -should usually choose for top-level language constructs inside -the code chunk (instead of 0). +FIRST-COLUMN is the column the indentation engine of the sub-mode +should use for top-level language constructs inside the code +chunk (instead of 0). -START to END is the region of the code chunk. See function -`prog-widen' for additional info. +START and END specify the region of the code chunk. END can be +nil, which stands for the value of `point-max'. The function +`prog-widen' uses this to restore restrictions imposed by the +sub-mode's indentation engine. PREVIOUS-CHUNKS, if non-nil, provides the indentation engine of -the sub mode with the virtual context of the code chunk. Valid +the sub-mode with the virtual context of the code chunk. Valid values are: - - A string containing code which the indentation engine can + - A string containing text which the indentation engine can consider as standing in front of the code chunk. To cache the string's calculated syntactic information for repeated calls - with the same string, it is valid and expected for the inner - mode to add text-properties to the string. + with the same string, the sub-mode can add text-properties to + the string. A typical use case is for grammars with code chunks which are - to be indented like function bodies - the string would contain - a corresponding function header. + to be indented like function bodies -- the string would contain + the corresponding function preamble. - - A function called with the start position of the current - chunk. It will return either the region of the previous chunk - as (PREV-START . PREV-END) or nil if there is no further - previous chunk. + - A function, to be called with the start position of the current + chunk. It should return either the region of the previous chunk + as (PREV-START . PREV-END), or nil if there is no previous chunk. - A typical use case are literate programming sources - the - function would successively return the code chunks of the - previous macro definitions for the same name.") + A typical use case are literate programming sources -- the + function would successively return the previous code chunks.") (defun prog-indent-sexp (&optional defun) "Indent the expression after point. @@ -113,8 +115,8 @@ instead." (defun prog-widen () "Remove restrictions (narrowing) from current code chunk or buffer. -This function can be used instead of `widen' in any function used -by the indentation engine to make it respect the value +This function should be used instead of `widen' in any function used +by the indentation engine to make it respect the value of `prog-indentation-context'. This function (like `widen') is useful inside a @@ -122,8 +124,8 @@ This function (like `widen') is useful inside a narrowing is in effect." (let ((chunk (cadr prog-indentation-context))) (if chunk - ;; no widen necessary here, as narrow-to-region changes (not - ;; just narrows) existing restrictions + ;; No call to `widen' is necessary here, as narrow-to-region + ;; changes (not just narrows) the existing restrictions (narrow-to-region (car chunk) (or (cdr chunk) (point-max))) (widen))))