hitt@neon.Stanford.EDU (Daniel Hitt) (04/08/91)
Is there a pre-defined mode or minor mode for editing objective-C files in emacs? Objective-C comments seem to confuse the indentation in a file. If this is an FAQ or RTFM please give a reference . . . dan
melling@cs.psu.edu (Michael D Mellinger) (04/08/91)
In article <1991Apr8.042756.19974@neon.Stanford.EDU> hitt@neon.Stanford.EDU (Daniel Hitt) writes:
Is there a pre-defined mode or minor mode for editing objective-C files
in emacs? Objective-C comments seem to confuse the indentation in
a file.
If this is an FAQ or RTFM please give a reference . . .
dan
An Objective C mode does not exist. You could try using a C++ mode;
the comments are the same. Try looking at tut.cis.ohio-state.edu
pub/gnu/emacs/elisp-archive.
-Mike
preston@LL.MIT.EDU (Steven Preston) (04/11/91)
>>>>> In article <sx5G!_6k1@cs.psu.edu>, melling@cs.psu.edu (Michael D Mellinger) writes: > Nntp-Posting-Host: sunws5.sys.cs.psu.edu > In article <1991Apr8.042756.19974@neon.Stanford.EDU> hitt@neon.Stanford.EDU (Daniel Hitt) writes: > Is there a pre-defined mode or minor mode for editing objective-C files > in emacs? Objective-C comments seem to confuse the indentation in > a file. > If this is an FAQ or RTFM please give a reference . . . > dan > An Objective C mode does not exist. You could try using a C++ mode; > the comments are the same. Try looking at tut.cis.ohio-state.edu > pub/gnu/emacs/elisp-archive. I wrote one long ago that works fairly well. The main bug is that you can't have certain syntax characters in a // type comment. This bug is most often tickled by having apostrophes (like in a contraction) in the comment. Such comments can be enclosed in ordinary /* */ comments; doing so will allow indentation to work, but will confuse some other functions, like backward-sexp (ESC C-b). So I try to avoid apostrophes in comments altogether. Anyway, here is the code. It's not really a mode, but rather a redefinition of a few c-mode functions. You can load this in your .emacs file. --------------------8<----------------8<-------------------------- ;;(defun c-mode-fix-apostrophe () ;; (modify-syntax-entry ?\' "/" c-mode-syntax-table) ;;the above makes an apostrophe an escape character to emacs ;;DANGER -- this makes emacs ignore unmatched single quotes ;; so they can be used as apostrophe's in //-style ;; comments. ;; ) ;;(setq c-mode-hook 'c-mode-fix-apostrophe) (defun skip-objc-comment-backward (lim) "If point is in middle of objective-c style comment, then skip backward to first slash (/), but don't skip past LIM" (let ((cur (point)) (in-quote nil) line-beg line-end) (end-of-line) (setq line-end (point)) (beginning-of-line) (setq line-beg (point)) (goto-char cur) (search-backward "//" line-beg t) ;; ;;If we found a // that is in a string ;;we must ignore it. We assume it is in ;;a string if there are an odd number of ;;double quotes between point and end of line. ;; NOTE: this will fail if unmatched double quotes are ;; placed in //-style comments. ;; Such quotes will confuse (parse-partial-sexp) anyway ;; and since that function is defined in the emacs ;; kernal and not in emacs-lisp, I don't want to ;; change it. ;; (setq cur (point)) (while (search-forward "\"" line-end t) (setq in-quote (null in-quote))) (if in-quote (end-of-line) (goto-char cur)) ) (goto-char (max (point) lim)) ) (defun at-beginning-of-line () (let ((cur (point)) result) (beginning-of-line) (setq result (= (point) cur)) (goto-char cur) result)) (defun skip-white-space-and-objc-comment-backward (lim) "Skips backward over sequence of white space and objective-c comments" (interactive) (skip-objc-comment-backward lim) (skip-chars-backward " \t\f" lim) (while (and (> (point) lim) (at-beginning-of-line)) (forward-char -1) (skip-objc-comment-backward lim) (skip-chars-backward " \t\f" lim)) ) ;; this replaces a c-mode function (defun c-backward-to-noncomment (lim) (let (opoint stop) (while (not stop) ;; instead of (skip-chars-backward " \t\n\f" lim) (skip-white-space-and-objc-comment-backward lim) (setq opoint (point)) (if (and (>= (point) (+ 2 lim)) (save-excursion (forward-char -2) (looking-at "\\*/"))) (search-backward "/*" lim 'move) (beginning-of-line) (skip-chars-forward " \t") (setq stop (or (not (looking-at "#")) (<= (point) lim))) (if stop (goto-char opoint) (beginning-of-line)))))) ;; this replaces a c-mode function (defun calculate-c-indent (&optional parse-start) "Return appropriate indentation for current line as C code. In usual case returns an integer: the column to indent to. Returns nil if line starts inside a string, t if in a comment." (save-excursion (beginning-of-line) (let ((indent-point (point)) (case-fold-search nil) state containing-sexp) (if parse-start (goto-char parse-start) (beginning-of-defun)) (while (< (point) indent-point) (setq parse-start (point)) (setq state (parse-partial-sexp (point) indent-point 0)) (setq containing-sexp (car (cdr state)))) (cond ((or (nth 3 state) (nth 4 state)) ;; return nil or t if should not change this line (nth 4 state)) ((null containing-sexp) ;; Line is at top level. May be data or function definition, ;; or may be function argument declaration. ;; Indent like the previous top level line ;; unless that ends in a closeparen without semicolon, ;; in which case this line is the first argument decl. (goto-char indent-point) (skip-chars-forward " \t") (if (= (following-char) ?{) 0 ; Unless it starts a function body (c-backward-to-noncomment (or parse-start (point-min))) ;; Look at previous line that's at column 0 ;; to determine whether we are in top-level decls ;; or function's arg decls. Set basic-indent accordinglu. (let ((basic-indent (save-excursion (re-search-backward "^[^ \^L\t\n#]" nil 'move) (if (and (looking-at "\\sw\\|\\s_") (looking-at ".*(") (progn (goto-char (1- (match-end 0))) (forward-sexp 1) (and (< (point) indent-point) (not (memq (following-char) '(?\, ?\;)))))) c-argdecl-indent 0)))) ;; Now add a little if this is a continuation line. (+ basic-indent (if (or (bobp) (memq (preceding-char) '(?\) ?\; ?\}))) 0 c-continued-statement-offset))))) ((/= (char-after containing-sexp) ?{) ;; line is expression, not statement: ;; indent to just after the surrounding open. (goto-char (1+ containing-sexp)) (current-column)) (t ;; Statement level. Is it a continuation or a new statement? ;; Find previous non-comment character. (goto-char indent-point) (c-backward-to-noncomment containing-sexp) ;; Back up over label lines, since they don't ;; affect whether our line is a continuation. (while (or (eq (preceding-char) ?\,) (and (eq (preceding-char) ?:) (or (eq (char-after (- (point) 2)) ?\') (memq (char-syntax (char-after (- (point) 2))) '(?w ?_))))) (if (eq (preceding-char) ?\,) (c-backward-to-start-of-continued-exp containing-sexp)) (beginning-of-line) (c-backward-to-noncomment containing-sexp)) ;; Now we get the answer. (if (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?\{))) ;; This line is continuation of preceding line's statement; ;; indent c-continued-statement-offset more than the ;; previous line of the statement. (progn (c-backward-to-start-of-continued-exp containing-sexp) (+ c-continued-statement-offset (current-column) (if (save-excursion (goto-char indent-point) (skip-chars-forward " \t") (eq (following-char) ?{)) c-continued-brace-offset 0))) ;; This line starts a new statement. ;; Position following last unclosed open. (goto-char containing-sexp) ;; Is line first statement after an open-brace? (or ;; If no, find that first statement and indent like it. (save-excursion (forward-char 1) (let ((colon-line-end 0)) (while (progn (skip-chars-forward " \t\n") (looking-at "#\\|/\\*\\|case[ \t\n].*:\\|[a-zA-Z0-9_$]*:\\|//")) ;; Skip over comments and labels following openbrace. ;; The additional case of "//" is for objective-c comments (cond ((= (following-char) ?\#) (forward-line 1)) ((looking-at "//") (forward-line 1)) ((= (following-char) ?\/) (forward-char 2) (search-forward "*/" nil 'move)) ;; case or label: (t (save-excursion (end-of-line) (setq colon-line-end (point))) (search-forward ":")))) ;; The first following code counts ;; if it is before the line we want to indent. (and (< (point) indent-point) (if (> colon-line-end (point)) (- (current-indentation) c-label-offset) (current-column))))) ;; If no previous statement, ;; indent it relative to line brace is on. ;; For open brace in column zero, don't let statement ;; start there too. If c-indent-level is zero, ;; use c-brace-offset + c-continued-statement-offset instead. ;; For open-braces not the first thing in a line, ;; add in c-brace-imaginary-offset. (+ (if (and (bolp) (zerop c-indent-level)) (+ c-brace-offset c-continued-statement-offset) c-indent-level) ;; Move back over whitespace before the openbrace. ;; If openbrace is not first nonwhite thing on the line, ;; add the c-brace-imaginary-offset. (progn (skip-chars-backward " \t") (if (bolp) 0 c-brace-imaginary-offset)) ;; If the openbrace is preceded by a parenthesized exp, ;; move to the beginning of that; ;; possibly a different line (progn (if (eq (preceding-char) ?\)) (forward-sexp -1)) ;; Get initial indentation of the line we are on. (current-indentation)))))))))) --------------------8<----------------8<-------------------------- -- Steve Preston