├── README.md └── openbsd-knf-style.el /README.md: -------------------------------------------------------------------------------- 1 | # OpenBSD KNF for Emacs # 2 | 3 | [OpenBSD](http://www.openbsd.org) uses Kernel Normal Form (KNF) for formatting C 4 | code. For details, see 5 | [style(9)](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man9/style.9). 6 | 7 | While KNF is a simple set of rules, it can be difficult to find editor support. 8 | Some of the rules go against common conventions used by editors. The biggest 9 | obstacle is our 4 space continuation rule. A lot of other style guides will 10 | indent based on the context such as indenting function arguments. The OpenBSD 11 | style guide is rigid and always uses tabs for first level indenting and tabs 12 | plus 4 space indents for the second level indenting. 13 | 14 | While this tries to be compliant with KNF, it is not perfect. It's good enough 15 | that I have been using it for over a year with OpenBSD code. If you want to 16 | write a tool that can handle KNF perfectly, adding support to clang-format 17 | would be a better (and more involved) solution. 18 | 19 | ## Usage ## 20 | 21 | There are several ways of incorporating this into your Emacs setup. 22 | 23 | This assumes you want to use the `~/.emacs.d` convention and have placed the 24 | style file in `~/.emacs.d/elisp/openbsd-knf-style.el`. 25 | 26 | This is a simple `~/.emacs.d/init.el` that enables OpenBSD KNF: 27 | 28 | ```lisp 29 | ;; Emacs 24.5 config 30 | (add-to-list 'load-path "~/.emacs.d/elisp/") 31 | 32 | ;; OpenBSD KNF for C/C++ 33 | (require 'openbsd-knf-style) 34 | (c-add-style "OpenBSD" openbsd-knf-style) 35 | (setq c-default-style '((c-mode . "OpenBSD"))) 36 | ``` 37 | 38 | Here's a slightly more realistic `~/.emacs.d/init.el`: 39 | 40 | ```lisp 41 | ;; Emacs 24.5 config 42 | (add-to-list 'load-path "~/.emacs.d/elisp/") 43 | 44 | (line-number-mode 1) 45 | (column-number-mode 1) 46 | (auto-compression-mode 1) 47 | 48 | (setq search-highlight 1) 49 | (setq query-replace-highlight 1) 50 | (setq show-paren-delay 0 51 | show-paren-style 'parenthesis) 52 | (setq blink-matching-paren t) 53 | (transient-mark-mode 1) 54 | (show-paren-mode 1) 55 | 56 | ;; General coding style. 57 | (setq-default show-trailing-whitespace t) 58 | (setq whitespace-style '(trailing lines space-before-tab) 59 | whitespace-line-column 80) 60 | (global-whitespace-mode 1) 61 | (global-font-lock-mode 1) 62 | 63 | ;; OpenBSD KNF for C/C++ 64 | (require 'openbsd-knf-style) 65 | (c-add-style "OpenBSD" openbsd-knf-style) 66 | (setq c-default-style '((c-mode . "OpenBSD"))) 67 | 68 | ;; In the modeline, show which function you are currently in. 69 | (add-hook 'c-mode-common-hook 70 | (lambda () 71 | (when (derived-mode-p 'c-mode 'c++-mode 'java-mode) 72 | (which-func-mode 1)))) 73 | 74 | ;; Dired shows all files by default. Use dired-x to stop displaying junk. 75 | (add-hook 'dired-load-hook 76 | (lambda () 77 | (load "dired-x") 78 | ;; I like to use '..' to navigate with dired so omit it here. 79 | (setq dired-omit-files "^\\.?#\\|^\\.$") 80 | )) 81 | (add-hook 'dired-mode-hook 82 | (lambda () 83 | (dired-omit-mode 1) 84 | )) 85 | ``` 86 | 87 | ## Limitations ## 88 | 89 | In practice, this works 95-100% of the time for me when editing code that's 90 | already in KNF format. It's 80-90% when applying KNF to a file that wasn't 91 | using it before because you're more likely to run into edge cases. 92 | 93 | -------------------------------------------------------------------------------- /openbsd-knf-style.el: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; OpenBSD KNF style 3 | ;; 4 | ;; Copyright (c) 2014,2015 Doug Hogan 5 | ;; Copyright (c) 2005 Nicholas Marriott 6 | ;; 7 | ;; Permission to use, copy, modify, and distribute this software for any 8 | ;; purpose with or without fee is hereby granted, provided that the above 9 | ;; copyright notice and this permission notice appear in all copies. 10 | ;; 11 | ;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | ;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | ;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | ;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | ;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | ;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | ;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | ;; 19 | 20 | ;; This function is from nicm@ 21 | (defun openbsd-knf-space-indent (langelem) 22 | "Indents either 4 spaces or none. 23 | 24 | This function is from nicm@ and also in gsoares@'s config. 25 | Most useful with c-offset-alist entries that are lists such as 26 | arglist-cont-nonempty" 27 | (save-excursion 28 | (goto-char (cdr langelem)) 29 | (setq syntax (car (car (c-guess-basic-syntax)))) 30 | (while (or (eq syntax 'arglist-intro) 31 | (or (eq syntax 'arglist-cont) 32 | (eq syntax 'arglist-cont-nonempty))) 33 | (forward-line -1) 34 | (setq syntax (car (car (c-guess-basic-syntax))))) 35 | (beginning-of-line) 36 | (re-search-forward "[^ \t]" (c-point 'eol)) 37 | (goto-char (+ (match-beginning 0) 4)) 38 | (vector (current-column)))) 39 | 40 | ;; OpenBSD KNF that doug@ uses. 41 | (defconst openbsd-knf-style 42 | '( 43 | ;; Debugging 44 | ;; (c-echo-syntactic-information-p . t) ;; display C-c C-s when hit 'tab' 45 | ;; 46 | ;; General settings that should be enabled in c-mode 47 | (indent-tabs-mode . t) ;; use tabs whenever feasible 48 | (fill-column . 80) ;; Assume KNF tries to maintain 80 char lines 49 | (show-trailing-whitespace . t) ;; KNF says to not have trailing WS 50 | (tab-width . 8) ;; When displaying literal tab, show 8 spaces 51 | ;; c-mode 52 | (c-progress-interval . 1) ;; display progress meter during long indents 53 | (c-basic-offset . 8) ;; KNF uses 8 space tabs 54 | (c-comment-only-line-offset . 0) ;; don't indent comments extra 55 | (c-backspace-function . delete-backward-char) 56 | (c-delete-function . delete-char) 57 | (c-syntactic-indentation-in-macros . t) ;; indent inside macro defs 58 | (c-tab-always-indent . t) ;; indent line: Use C-q 'tab' to insert literal 59 | (c-continued-statement-offset 0) 60 | ;; (c-electric-flag . nil) ;; if you don't like auto-indent 61 | (c-electric-continued-statement . t) 62 | ;; 63 | (c-indent-comments-syntactically-p . nil) 64 | ;; 65 | ;; Offsets for the various c-mode symbols. Offsets are sometimes based 66 | ;; upon other offsets. For instance, arglist-intro is the 1st argument 67 | ;; line. If you define arglist-cont, it uses arglist-intro plus that. 68 | ;; c-echo-syntactic-information-p is your friend when debugging indents. 69 | ;; 70 | ;; [N] means absolute column. All the others are relative. 71 | ;; 0 = no extra indentation. For literal column 0, use [0] 72 | ;; N = extra N spaces. For literal column N, use [N] 73 | ;; ++ = c-basic-offset * 2 74 | ;; -- = c-basic-offset * -2 75 | ;; + = c-basic-offset * 1 76 | ;; - = c-basic-offset * -1 77 | ;; * = c-basic-offset * 0.5 78 | ;; / = c-basic-offset * -0.5 79 | (c-offsets-alist . ( 80 | ;; Literal symbols 81 | (func-decl-cont . 0) ; C++ style func mod 82 | (block-open . 0) ; '{' for block 83 | (label . [1]) ; goto label in column 1 84 | (comment-intro . 0) ; C comment 85 | (cpp-macro . [0]) ; #define in column 0 86 | ;; Multiline macro symbols 87 | (cpp-define-intro . [0]) ; first list = column 0 88 | (cpp-macro-cont . +) ; add'l lines in macro 89 | ;; Function symbols 90 | (defun-open . 0) ; '{' alone for func 91 | (defun-close . 0) ; '}' alone for func 92 | (defun-block-intro . +) ; first line of func 93 | (topmost-intro . 0) ; outermost part 94 | (topmost-intro-cont . 0) ; outermost part cont 95 | (statement . 0) ; func stmt (already off) 96 | ;; XXX statement-cont should be 4 unless 97 | ;; it is part of a macro, then 8. 98 | (statement-cont . *) ; continue stmt 99 | ;; Class symbols. XXX Should add support since there 100 | ;; is a little C++ in the tree (GNU) 101 | ;; Java 102 | ;; K&R 103 | (knr-argdecl-intro . +) ; rare K&R (from KNF) 104 | (knr-argdecl . 0) ; add'l indent for rest 105 | ;; Conditional construct symbols 106 | (block-close . 0) ; '}' for block 107 | (statement-block-intro . +) ; stmt in loop/cond 108 | (substatement . +) ; non-braced stmt if() 109 | (substatement-open . 0) ; '{' in loop/cond 110 | (substatement-label . [1]) ; goto label in loop/cond 111 | (do-while-closure . 0) ; 'while' alone in 'do' 112 | (else-clause . 0) ; 'else' when not nested 113 | ;; Brace list symbols 114 | (brace-list-close . 0) ; enum/agg list close 115 | (brace-list-intro . +) ; 1st line of enum/agg 116 | (brace-list-entry . 0) ; add'l indent for entries 117 | (brace-list-open . 0) ; enum/agg init open 118 | ;; Switch statement symbols 119 | (statement-case-open . +) ; '{' in case 120 | (statement-case-intro . +) ; 1st line in case stmt 121 | (case-label . 0) ; case label in switch 122 | ;; Paren list symbols 123 | ;; XXX This is typically a list so need to handle it 124 | ;; differently from the rest. Emacs adds the indents. 125 | (arglist-intro . openbsd-knf-space-indent) ; 1st line 126 | (arglist-cont . openbsd-knf-space-indent) 127 | (arglist-cont-nonempty . openbsd-knf-space-indent) 128 | (arglist-close . 0) ; ')' alone 129 | ;; External scope symbols 130 | (extern-lang-open . [0]) ; '{' alone in 'extern C' 131 | (extern-lang-close . [0]) ; '}' alone in 'extern C' 132 | (inextern-lang . +) ; lines inside 'extern C' 133 | ;; Statement block 134 | (inexpr-statement . +))) ; gcc extension stmt expr 135 | ;; If not specified, the default is "before after". All variables are 136 | ;; defined here. 137 | (c-hanging-braces-alist . ( 138 | ;; All variables 139 | (defun-open before after) ; function, enum 140 | (defun-close before after) ; function 141 | (class-open after) ; struct too 142 | (class-close before after) 143 | (inline-open after) 144 | (inline-close before after) 145 | (block-open after) 146 | (block-close . c-snug-do-while) 147 | (statement-cont after) 148 | (substatement-open after) 149 | (statement-case-open before after) 150 | (brace-list-open after) 151 | (brace-list-close before close) 152 | (brace-list-intro after) 153 | (brace-entry-open after) 154 | (extern-lang-open after) 155 | (extern-lang-close before after) 156 | (namespace-open after) ;; C++ 157 | (namespace-close before afetr) ;; C++ 158 | (module-open after) ;; CORBA 159 | (module-close before after) ;; CORBA 160 | (composition-open after) ;; CORBA 161 | (composition-close before after) ;; CORBA 162 | (inexpr-class-open after) 163 | (inexpr-class-close before after) 164 | (arglist-cont-nonempty before after))) 165 | ;; Whether to auto-insert newline before/after colon 166 | (c-hanging-colons-alist . ((case-label after) 167 | (label after) 168 | (access-label after) ;; C++ 169 | (member-init-intro before) 170 | (inher-intro))) 171 | ;; Whether to insert newlines after ';' or ',' 172 | (c-hanging-semi&comma-criteria . ( 173 | ;; supress newline when next line non-blank 174 | c-semi&comma-no-newlines-before-nonblanks 175 | ;; suppress newline in paren (for loop etc) 176 | c-semi&comma-inside-parenlist 177 | ;; supress newline for one liner 178 | c-semi&comma-no-newlines-for-oneline-inliners)) 179 | ;; When autonewline mode is enabled, clean up some extra newlines 180 | (c-cleanup-list . (brace-else-brace ; } else { 181 | brace-elseif-brace ; } else if { 182 | brace-catch-brace ; } catch (...) { 183 | ;; empty-defun-braces ; {} instead of multiple lines 184 | defun-close-semi ; struct: no \n between '}' and ';' 185 | list-close-comma ; remove final comma 186 | scope-operator 187 | ;; space-before-funcall ; GNU standard 188 | ;; compact-empty-funcall ; another GNU standard 189 | ;; comment-close-slash ; term comment with slash 190 | )) 191 | )) 192 | 193 | (defun openbsd-set-knf-style () 194 | "Set OpenBSD style in a 'c-mode-common-hook'. 195 | Or interactively enable it in a buffer." 196 | (interactive) 197 | (c-add-style "OpenBSD" openbsd-knf-style t)) 198 | 199 | (provide 'openbsd-knf-style) 200 | --------------------------------------------------------------------------------