Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157620880
D57008.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D57008.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D57008: tools/tools/editing/freebsd.el: Add support for tree-sitter modes
Attached
Detach File
Event Timeline
Log In to Comment