;;; cc-guess.el --- guess indentation values by scanning existing code ;; Copyright (C) 1985,1987,1992-2003, 2004, 2005 Free Software Foundation, ;; Inc. ;; Author: 1994-1995 Barry A. Warsaw ;; Maintainer: Unmaintained ;; Created: August 1994, split from cc-mode.el ;; Version: See cc-mode.el ;; Keywords: c languages oop ;; This file is not part of GNU Emacs. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; ;; This file contains routines that help guess the cc-mode style in a ;; particular region/buffer. It is provided for example and ;; experimentation only. It is not supported in anyway. Note that ;; style guessing is lossy! ;; ;; The way this is intended to be run is for you to mark a region of ;; code to guess the style of, then run the command, `cc-guess-region'. ;;; Code: (eval-when-compile (let ((load-path (if (and (boundp 'byte-compile-dest-file) (stringp byte-compile-dest-file)) (cons (file-name-directory byte-compile-dest-file) load-path) load-path))) (load "cc-bytecomp" nil t))) (cc-require 'cc-defs) (cc-require 'cc-engine) (defvar cc-guessed-style nil "Currently guessed style.") (defvar cc-guess-delta-accumulator nil) ;; Accumulated sampled indent information. Information is represented ;; in a list. Each element in it has following structure: ;; ;; (syntactic-symbol ((indentation-delta1 . number-of-times1) ;; (indentation-delta2 . number-of-times2) ;; ...)) ;; ;; This structure is built by `cc-guess-accumulate-delta'. ;; ;; Here we call the pair (indentation-delta1 . number-of-times1) a ;; counter. `cc-guess-sort-delta-accumulator' sorts the order of ;; counters by number-of-times. (defconst cc-guess-conversions '((c . c-lineup-C-comments) (inher-cont . c-lineup-multi-inher) (string . -1000) (comment-intro . c-lineup-comment) (arglist-cont-nonempty . c-lineup-arglist) (arglist-close . c-lineup-close-paren) (cpp-macro . -1000))) (defun cc-guess (&optional accumulate) "Apply `cc-guess-region' on the whole current buffer. If given a prefix argument (or if the optional argument ACCUMULATE is non-nil) then the previous guess is extended, otherwise a new guess is made from scratch." (interactive "P") (cc-guess-region (point-min) (point-max) accumulate)) (defun cc-guess-install () "Set the indentation style from the last guessed style (`cc-guessed-style')." (interactive) (setq c-offsets-alist (cc-guess-merge-styles cc-guessed-style c-offsets-alist))) (defun cc-guess-region (start end &optional accumulate) "Set the indentation style by examining the indentation in a region of code. Every line of code in the region is examined and the indentation values of the various syntactic symbols in `c-offset-alist' are guessed. Frequencies of use are taken into account, so minor inconsistencies in the indentation style shouldn't produce wrong guesses. The guessed style is put into `cc-guessed-style'. It's also merged into `c-offsets-alist'. Guessed offsets takes precedence over existing ones on `c-offsets-alist'. If given a prefix argument (or if the optional argument ACCUMULATE is non-nil) then the previous guess is extended, otherwise a new guess is made from scratch. Note that the larger the region to guess in, the slower the guessing." (interactive "r\nP") (let ((delta-accumulator (when accumulate cc-guess-delta-accumulator)) (reporter (when (fboundp 'make-progress-reporter) (make-progress-reporter "Sampling Indentation " start end)))) ;; ;; Sampling stage ;; (save-excursion (goto-char start) (while (< (point) end) (c-save-buffer-state ((syntax (c-guess-basic-syntax)) (relpos (car (cdr (car syntax)))) (symbol (car (car syntax)))) ;; TBD: for now I can't guess indentation when more than 1 ;; symbol is on the list, nor for symbols without relpos's ;; ;; I think it is too stricted for ((topmost-intro) (comment-intro)). ;; -- Masatake (unless (or ; (/= 1 (length syntax)) (not (numberp relpos)) (eq (line-beginning-position) (line-end-position))) (setq delta-accumulator (cc-guess-accumulate-delta delta-accumulator symbol (- (progn (back-to-indentation) (current-column) ) (save-excursion (goto-char relpos) (current-column))))))) (when reporter (progress-reporter-update reporter (point))) (forward-line 1))) (when reporter (progress-reporter-done reporter)) ;; ;; Guessing stage ;; (setq delta-accumulator (cc-guess-sort-delta-accumulator delta-accumulator) cc-guess-delta-accumulator delta-accumulator) (let* ((typical-style (cc-guess-make-style delta-accumulator)) (merged-style (cc-guess-merge-styles (copy-list cc-guess-conversions) typical-style))) (setq cc-guessed-style merged-style c-offsets-alist (cc-guess-merge-styles merged-style c-offsets-alist))))) (defun cc-guess-accumulate-delta (accumulator symbol delta) ;; Added SYMBOL and DELTA to ACCUMULATOR. See ;; `cc-guess-delta-accumulator' about the structure of ACCUMULATOR. (let* ((entry (assoc symbol accumulator)) (counters (cdr entry)) counter) (if entry (progn (setq counter (assoc delta counters)) (if counter (setcdr counter (1+ (cdr counter))) (setq counters (cons (cons delta 1) counters)) (setcdr entry counters)) accumulator) (cons (cons symbol (cons (cons delta 1) nil)) accumulator)))) (defun cc-guess-sort-delta-accumulator (accumulator) ;; Sort the each element of ACCUMULATOR by the number-of-times. See ;; `cc-guess-delta-accumulator' for more details. (mapcar (lambda (entry) (let ((symbol (car entry)) (counters (cdr entry))) (cons symbol (sort counters (lambda (a b) (if (> (cdr a) (cdr b)) t (and (eq (cdr a) (cdr b)) (< (car a) (car b))))))))) accumulator)) (defun cc-guess-make-style (accumulator) ;; Throw away the rare cases in accumulator and make a style structure. (mapcar (lambda (entry) (cons (car entry) (car (car (cdr entry))))) accumulator)) (defun cc-guess-merge-styles (strong weak) ;; Merge two styles into one. When two styles has the same symbol ;; entry, give STRONG priority over WEAK. (mapc (lambda (weak-elt) (unless (assoc (car weak-elt) strong) (setq strong (cons weak-elt strong)))) weak) strong) (defun cc-guess-view-style () "Show `cc-guessed-style'." (interactive) (with-output-to-temp-buffer "*Indentation Guessing Result*" (pp cc-guessed-style))) (cc-provide 'cc-guess) ;;; cc-guess.el ends here