Page MenuHomeFreeBSD

D57008.diff
No OneTemporary

D57008.diff

diff --git a/tools/tools/editing/freebsd.el b/tools/tools/editing/freebsd.el
--- a/tools/tools/editing/freebsd.el
+++ b/tools/tools/editing/freebsd.el
@@ -1,40 +1,149 @@
-;;; This function switches C-mode so that it indents almost everything
-;;; as specified in FreeBSD's style(9). Tested with emacs-19.34 and
-;;; xemacs-20.4.
-;;;
-;;; Use "M-x bsd" in a C mode buffer to activate it.
-;;;
-;;; The only problem I found is top-level indenting:
-;;;
-;;; We want function definitions with the function name at the beginning
-;;; of a second line after the return type specification in the first:
-;;; > int
-;;; > foo(int bla)
-;;; But emacs c-mode can't treat this differently from other multiple-line
-;;; toplevel constructs:
-;;; > const char *const bar =
-;;; > "sometext";
-;;; which means the second line must be indented by hand.
-;;;
-;;; To make this the default, use a line like this, but you can't easily
-;;; switch back to default GNU style, since the old state isn't saved.
-;;; (add-hook 'c-mode-common-hook 'bsd)
-;;; As long as you don't have this in the c-mode hook you can edit GNU
-;;; and BSD style C sources within one emacs session with no problem.
-;;;
-;;; Please report problems and additions directly to cracauer@freebsd.org
-
-(defun bsd () (interactive)
- (c-set-style "bsd")
- (setq indent-tabs-mode t)
- ;; Use C-c C-s at points of source code so see which
- ;; c-set-offset is in effect for this situation
- (c-set-offset 'defun-block-intro 8)
- (c-set-offset 'statement-block-intro 8)
- (c-set-offset 'statement-case-intro 8)
- (c-set-offset 'substatement-open 4)
- (c-set-offset 'substatement 8)
- (c-set-offset 'arglist-cont-nonempty 4)
- (c-set-offset 'inclass 8)
- (c-set-offset 'knr-argdecl-intro 8)
- )
+;;; freebsd.el --- FreeBSD style(9) formatting -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;; This library customizes Emacs modes for editing C and related source code to
+;; support FreeBSD's style(9) formatting. It handles both the classic modes and
+;; the newer tree-sitter modes.
+;;
+;; After loading this file, use "M-x freebsd" to activate it.
+;;
+;; To make this the default, add the configuration below to your Emacs
+;; initialization.
+;;
+;; Classic modes:
+;; (add-hook 'c-mode-common-hook 'freebsd)
+;;
+;; Note: With the hook, you cannot easily switch back to default GNU style,
+;; since the old state isn't saved.
+;;
+;; Tree-sitter modes:
+;; (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
+;; (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
+;; (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode))
+;;
+;; (add-hook 'c-ts-mode-hook 'freebsd)
+;; (add-hook 'c++-ts-mode-hook 'freebsd)
+;;
+;; For the classic modes, there are limitations with top-level indenting: We
+;; want function definitions with the function name at the beginning of a second
+;; line after the return type specification in the first:
+;;
+;; > int
+;; > foo(int bla)
+;;
+;; But emacs c-mode can't treat this differently from other multiple-line
+;; toplevel constructs:
+;;
+;; > const char *const bar =
+;; > "sometext";
+;;
+;; which means the second line must be indented by hand.
+;;
+;; Please report problems and additions to cracauer@freebsd.org and
+;; jrm@freebsd.org.
+
+;; Code:
+
+(defun freebsd--find-ancestor (node type-rx)
+ "Walk up from NODE returning the first ancestor matching TYPE-RX, or nil."
+ (let ((p (treesit-node-parent node)))
+ (while (and p (not (treesit-node-match-p p type-rx)))
+ (setq p (treesit-node-parent p)))
+ p))
+
+(defun freebsd--arglist-cont-indent (node _parent bol &rest _)
+ "Indent continuation lines in argument/parameter lists by 4 spaces.
+Walks up the syntax tree to find the enclosing argument_list or
+parameter_list, then indents 4 spaces past that line's indentation."
+ (when-let* ((list-node (freebsd--find-ancestor
+ node
+ (rx (or "argument_list" "parameter_list")))))
+ ;; Only fire when the node is on a different line than the opening paren.
+ (unless (= bol (save-excursion
+ (goto-char (treesit-node-start list-node))
+ (pos-bol)))
+ (save-excursion
+ (goto-char (treesit-node-start list-node))
+ (back-to-indentation)
+ (cons (pos-bol) (+ (current-column) 4))))))
+
+(defun freebsd--expr-cont-indent (node parent _bol &rest _)
+ "Indent expression continuations by 4 spaces past the containing statement.
+Handles binary, conditional, and assignment expressions that wrap across
+lines, e.g.:
+
+ z = a + really + long + statement +
+ two + lines;"
+ (when (and parent
+ (treesit-node-match-p
+ parent
+ (rx (or "binary_expression"
+ "conditional_expression"
+ "assignment_expression"))))
+ (when-let* ((stmt (freebsd--find-ancestor
+ node
+ (rx (or "expression_statement"
+ "declaration"
+ "return_statement"
+ "if_statement"
+ "while_statement"
+ "for_statement"
+ "do_statement"
+ "switch_statement")))))
+ (save-excursion
+ (goto-char (treesit-node-start stmt))
+ (back-to-indentation)
+ (cons (pos-bol) (+ (current-column) 4))))))
+
+(defun freebsd--init-declarator-cont-indent (_node parent _bol &rest _)
+ "Indent an init_declarator's value 4 spaces past its declaration.
+This implements style(9)'s 4-space continuation indent for variable
+initializations that span multiple lines, e.g.:
+
+ const char *const bar =
+ \"sometext\";"
+ (when (and parent
+ (string= (treesit-node-type parent) "init_declarator"))
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (back-to-indentation)
+ (cons (pos-bol) (+ (current-column) 4)))))
+
+(defun freebsd--ts-indent-rules ()
+ "Return FreeBSD-specific tree-sitter indent rules.
+Extends the built-in BSD style with style(9)-compliant 4-space
+continuation indentation for argument lists, parameter lists,
+multi-line expressions, and variable initializations."
+ (let* ((lang (if (derived-mode-p 'c-ts-mode) 'c 'cpp))
+ (bsd-rules (alist-get lang (c-ts-mode--simple-indent-rules lang 'bsd))))
+ `(freebsd--arglist-cont-indent
+ freebsd--expr-cont-indent
+ freebsd--init-declarator-cont-indent
+ ,@bsd-rules)))
+
+(defun freebsd ()
+ "Use FreeBSD style(9) formatting in the current buffer."
+ (interactive)
+ (setq-local indent-tabs-mode t)
+ (setq-local tab-width 8)
+ (if (derived-mode-p 'c-ts-mode 'c++-ts-mode)
+ ;; Tree-sitter
+ (progn
+ (c-ts-mode-set-style #'freebsd--ts-indent-rules)
+ (setq-local c-ts-indent-offset 8)
+ (setq-local treesit-font-lock-level 4))
+ ;; Classic c-mode
+ ;; Use C-c C-s at points of source code to see which
+ ;; c-set-offset is in effect for this situation.
+ (c-set-style "bsd")
+ (mapc (lambda (setting)
+ (c-set-offset (car setting) (cdr setting)))
+ '((defun-block-intro . 8)
+ (statement-block-intro . 8)
+ (statement-case-intro . 8)
+ (substatement-open . 4)
+ (substatement . 8)
+ (arglist-cont-nonempty . 4)
+ (inclass . 8)
+ (knr-argdecl-intro . 8)))))

File Metadata

Mime Type
text/plain
Expires
Sun, May 24, 12:33 PM (8 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33128621
Default Alt Text
D57008.diff (7 KB)

Event Timeline