(require 'cc-mode) (defgroup henrik nil "Henrik style support for C-like languages." :group 'tools) (defcustom henrik-column 75 "Column where Henrik characters are placed." :group 'henrik :type 'integer) (defcustom henrik-chars ";{}" "Henrik characters." :group 'henrik :type 'string) (defcustom henrik-progress-interval 5 "*Interval used to update progress status during long (de)henrikizing. If a number, percentage complete gets updated after each interval of that many seconds. To inhibit all messages during indentation, set this variable to nil." :type 'integer :group 'henrik) (defun henrik-char-p (ch) (memq ch (string-to-list henrik-chars))) (defun henrikize-line () "Henrikize the current line." (interactive) (save-excursion (end-of-line) (if (re-search-backward (concat "[" henrik-chars "]+$") (line-beginning-position) t) (progn (if (< (current-column) henrik-column) (insert-char ?\ (- henrik-column (current-column)))) (skip-chars-forward henrik-chars) (skip-chars-forward " \t\n") (while (henrik-char-p (char-after)) (backward-delete-char (skip-chars-backward " \t\n")) (forward-char) (skip-chars-forward " \t\n")) (backward-delete-char (skip-chars-backward " \t")) (or (char= (char-before) ?\n) (insert-char ?\n)) (c-indent-line nil t))))) (defun dehenrikize-line () "Dehenrikize the current line." (interactive) (save-excursion (beginning-of-line) (if (re-search-forward (concat "[ \t]+\\([" henrik-chars "]\\)") (line-end-position) t) (progn (replace-match "\\1") (c-indent-line nil t) (while (henrik-char-p (char-after)) (insert-char ?\n) (c-indent-line nil t) (forward-char)))))) (defun henrikize-region (start end) "Obfuscate region Henrik-style." (interactive "r") (henrik-do-region start end 'henrikize-line "Henrikizing")) (defun dehenrikize-region (start end) "Deobfuscate Henrik-style region so others can read it." (interactive "r") (henrik-do-region start end 'dehenrikize-line "Dehenrikizing")) ;; Everything below is more or less copied from cc-mode. (defun henrik-do-region (start end fn op) (save-excursion (goto-char start) ;; Advance to first nonblank line. (skip-chars-forward " \t\n") (beginning-of-line) (let ((endmark (copy-marker end))) (unwind-protect (progn (henrik-progress-init start end 'henrik-do-region op) (while (and (bolp) (not (eobp)) (< (point) endmark)) (henrik-progress-update op) ;; skip blank lines (skip-chars-forward " \t\n") (beginning-of-line) (funcall fn) (forward-line))) (set-marker endmark nil) (henrik-progress-fini 'henrik-do-region op))))) (defvar henrik-progress-info nil) (defun henrik-progress-init (start end context op) (cond ;; Be silent ((not henrik-progress-interval)) ;; Start the progress update messages. If this Emacs doesn't have ;; a built-in timer, just be dumb about it. ((not (fboundp 'current-time)) (message (concat op " region... (this may take a while)"))) ;; If progress has already been initialized, do nothing. otherwise ;; initialize the counter with a vector of: ;; [start end lastsec context] (henrik-progress-info) (t (setq henrik-progress-info (vector start (save-excursion (goto-char end) (point-marker)) (nth 1 (current-time)) context)) (message (concat op " region..."))) )) (defun henrik-progress-update (op) ;; update progress (if (not (and henrik-progress-info henrik-progress-interval)) nil (let ((now (nth 1 (current-time))) (start (aref henrik-progress-info 0)) (end (aref henrik-progress-info 1)) (lastsecs (aref henrik-progress-info 2))) ;; should we update? currently, update happens every 2 seconds, ;; what's the right value? (if (< henrik-progress-interval (- now lastsecs)) (progn (message (concat op " region... (%d%% complete)") (/ (* 100 (- (point) start)) (- end start))) (aset henrik-progress-info 2 now))) ))) (defun henrik-progress-fini (context op) ;; finished (if (not henrik-progress-interval) nil (if (or (eq context (aref henrik-progress-info 3)) (eq context t)) (progn (set-marker (aref henrik-progress-info 1) nil) (setq henrik-progress-info nil) (message (concat op " region... done")))))) (provide 'henrik)