emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: antlr-mode.el - need some support by python.el


From: Stefan Monnier
Subject: Re: antlr-mode.el - need some support by python.el
Date: Wed, 18 Feb 2015 12:56:11 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

>> Narrowing sucks, so no it's not a viable alternative.
> Do you suppose the submodes will implement prog-indentation-context support
> using something other than narrowing? It's a powerful approach.

They can choose to do so if it doesn't break some of the things they do,
of course, but forcing it upon them will lead to trouble.

> I think I'd rather change the indent-line-function API, to return the column
> offset.  Or add a new one, like `line-indentation-function'.

Agreed, but someone's got to do it.  FWIW I've appended code I've had in
my prog-mode.el for many years (e.g. long before add-function came
along ;-).

BTW, I consider any mode which needs auto-indentation to be
a "programming mode".  That includes LaTeX, XML, ... (which are also
text-modes, but I don't think the two are mutually exclusive).

>> Furthermore, I can imagine some cases where the inner mode may still
>> want to indent to a column smaller than LEFTMOST-COL for good reasons.
> I wonder what that is.

E.g. in latex-mode, a "\begin{verbatim}" has to go to column 0, no
matter what the context.

> But anyway, line-indentation-function would
> return a negative value in that case.

How would it know it has to do that (and how negative should it be) if
it's not told about LEFTMOST-COL?


        Stefan


;; Generic indentation support ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun prog-indent-line (&optional arg)
  "Reindent current line.
If ARG is non-nil, indent any additional lines of the same expression rigidly
along with this one."
  (interactive)
  (if arg
      ;; We could use it to reindent the sexp at point:
      ;; (indent-region (point)
      ;;                (progn (forward-sexp 1) (point)))
      ;; But Lisp-mode by default does "indent any additional lines of the
      ;; same expression rigidly along with this one.", so let's
      ;; reproduce that.
      (let ((old-indent (current-indentation)))
        (if (eq (indent-according-to-mode) 'noindent)
            (funcall (default-value 'indent-line-function)))
        (let ((new-indent (current-indentation))
              (beg (line-beginning-position 2))
              (end (save-excursion (beginning-of-line)
                                   (forward-sexp 1)
                                   (point))))
          (when (and (> end beg) (/= new-indent old-indent))
            (indent-code-rigidly beg end (- new-indent old-indent)))))
    ;; Normal case.
    (let* ((savep (point))
           (indent (condition-case nil
                       (save-excursion
                         (forward-line 0)
                         (skip-chars-forward " \t")
                         (if (>= (point) savep) (setq savep nil))
                         (or (prog-indent-calculate) 0))
                     (error 0))))
      (if (not (numberp indent))
          ;; If something funny is used (e.g. `noindent'), return it.
          indent
        (if (< indent 0) (setq indent 0)) ;Just in case.
        (if savep
            (save-excursion (indent-line-to indent))
          (indent-line-to indent))))))

(defvar prog-indent-calculate-functions
  '(prog-indent-calculate-in-string
    prog-indent-calculate-fixindent
    prog-indent-calculate-comment
    prog-indent-calculate-close-sexp)
  "Functions to indent the current line.
Each function is called in turn with no argument until one of them returns
  a non-nil value, which is then used as the column number to which point
  should be indented.
Each function is responsible for restoring point to its correct location
  for the next function to work properly.
Functions should expect to be sometimes called with point in
  the middle of a line, in which case they should pretend that the
  preceding text is on another line.")

(defun prog-indent-calculate ()
  "Compute the column at which point should be indented.
Point may be in the middle of a line, in which case this returns the column
at which point should be indented if it were at the beginning of a line.
May return `noindent' to indicate that point's indentation should not be
touched, typically because it is inside a string."
  (run-hook-with-args-until-success 'prog-indent-calculate-functions))

(defun prog-indent-calculate-fixindent ()
  "Don't indent the line if the magic string is there.
The magic string is \"fixindent\" alone inside a comment or at the end
of the line (preceded by a TAB) if no comment style is defined."
  (when (looking-at (concat ".*" (regexp-quote (or comment-start "\t"))
                            "[ \t]*fixindent[ \t]*"
                            (regexp-quote (or comment-end "\n"))))
    (current-indentation)))

(defun prog-indent-calculate-comment ()
  "Indentation of a comment.
The indentation used is the same as would be used for the line following
the comment, unless `comment-indent-function' says otherwise."
  ;; FIXME: This should be moved to newcomment.el.
  (let ((pos (point)))
    (when (and (not (looking-at "\\s-\\|\n")) (forward-comment 1))
      (or (save-excursion
            (goto-char pos)
            (funcall comment-indent-function))
          (save-excursion
            (skip-chars-forward " \t")
            (prog-indent-calculate))))))

(defun prog-indent-calculate-in-string ()
  "Indentation inside a string.  Don't touch it."
  (if (nth 3 (syntax-ppss)) 'noindent))

(defun prog-bolp ()
  (save-excursion (skip-chars-backward " \t") (bolp)))

(defun prog-indent-hanging-p ()
  "Non-nil if token at point is hanging.
A hanging token is a token that starts an sexp (e.g. an open parenthesis),
is not at the beginning of a line, and is at the end of a line."
  (and (not (prog-bolp))
       (looking-at "\\s(+[ \t]*$")))

(defun prog-indent-current ()
  "Current indentation at point.
Return the indentation currently used at point."
  (if (prog-indent-hanging-p)
      (prog-indent-calculate)
    (current-column)))

(defun prog-indent-calculate-close-sexp ()
  "Indentation of the closing token of an sexp."
  (and (looking-at "\\s)+")
       (save-excursion
         (goto-char (match-end 0))
         (forward-sexp -1)
         ;; Align with the matching opening token.
         (prog-indent-current))))




reply via email to

[Prev in Thread] Current Thread [Next in Thread]