| git.druid.rocks | index | druid520 | radium | radium-lang-c.el |
radium-lang-c.el
;;; radium-lang-c.el, c89, allman/bsd brace style, tabs -*- lexical-binding: t; -*-
(require 'cc-mode)
(c-add-style "radium-c89"
'("bsd"
(c-basic-offset . 8)
(indent-tabs-mode . t)
(c-offsets-alist . ((substatement-open . 0)
(statement-cont . 8)
(arglist-intro . 8)
(arglist-close . 0)))))
(setq-default c-default-style '((c-mode . "radium-c89")))
(add-hook 'c-mode-hook
(lambda ()
(setq indent-tabs-mode t
tab-width 8
c-basic-offset 8
;; cc-mode's own electric reindent (separate from
;; electric-indent-mode, which radium-defaults.el
;; already turns off globally) fires on braces/colons/
;; etc as i type them - same premature-tabs problem,
;; cc-mode-specific switch.
c-electric-flag nil)
(c-set-style "radium-c89")))
(add-to-list 'auto-mode-alist '("\\.c\\'" . c-mode))
(add-to-list 'auto-mode-alist '("\\.h\\'" . c-mode))
(defun radium-varinit-parse (line)
"parse a bare c declaration LINE into (type name array-p pointer-p),
or nil when it doesnt look like a plain single-declarator decl: no
\"=\" (already initialized), \"(\" (a call/prototype), \",\" (multiple
declarators - which one would i mean?) or \":\" (a bitfield), and not
a typedef/extern (neither takes an initializer here)."
(let ((l (string-trim line)) array-p)
(when (string-match "\\[\\([0-9]*\\)\\]\\s-*\\'" l)
(setq array-p t l (string-trim (substring l 0 (match-beginning 0)))))
(unless (or (string-empty-p l)
(string-match-p "[=(,:]" l)
(string-match-p "\\`\\(typedef\\|extern\\)\\_>" l))
(let ((tokens (split-string (replace-regexp-in-string "\\*" " * " l) "[ \t]+" t)))
(when (>= (length tokens) 2)
(let* ((name (car (last tokens)))
(type-tokens (butlast tokens))
(pointer-p (and (member "*" type-tokens) t))
(type (mapconcat #'identity type-tokens " ")))
(when (string-match-p "\\`[A-Za-z_][A-Za-z0-9_]*\\'" name)
(list type name array-p pointer-p))))))))
(defun radium-varinit-default (type array-p pointer-p)
"the zero-value i want for a c declaration of TYPE: {0} for an array
or a struct/union (c89's own all-fields-zero idiom), NULL for a
pointer, '\\0' for a bare char, 0.0 for float/double, else 0."
(cond
(array-p "{0}")
(pointer-p "NULL")
((string-match-p "\\_<char\\_>" type) "'\\0'")
((string-match-p "\\_<\\(float\\|double\\)\\_>" type) "0.0")
((string-match-p "\\_<\\(struct\\|union\\)\\_>" type) "{0}")
(t "0")))
(defun radium-varinit-trigger ()
"the instant i finish a bare declaration like `int i;' with its
closing semicolon, rewrite it in place to `int i = 0;' (or whatever
zero-value actually fits the type) - i almost never want an
uninitialized local, and typing the initializer by hand every single
time is the entire reason this exists."
(when (and (eq last-command-event ?\;)
(not (minibufferp))
(not (nth 8 (syntax-ppss))))
(let* ((eol (point))
(bol (line-beginning-position))
(parsed (radium-varinit-parse (buffer-substring-no-properties bol (1- eol)))))
(when parsed
(goto-char (1- eol))
(insert (format " = %s" (radium-varinit-default (nth 0 parsed) (nth 2 parsed) (nth 3 parsed))))))))
(add-hook 'c-mode-hook
(lambda ()
(add-hook 'post-self-insert-hook #'radium-varinit-trigger nil t)))
(provide 'radium-lang-c)