From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel,gmane.emacs.cedet Subject: Re: [CEDET-devel] CEDET completion-at-point-function Date: Sat, 14 Jun 2014 23:14:21 -0400 Message-ID: References: <53717C7E.60208@siege-engine.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1402802084 19954 80.91.229.3 (15 Jun 2014 03:14:44 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 15 Jun 2014 03:14:44 +0000 (UTC) Cc: emacs-devel@gnu.org, cedet-devel@lists.sourceforge.net, dgutov@gnu.org To: "Eric M. Ludlam" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Jun 15 05:14:38 2014 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Ww0ty-0003tR-8c for ged-emacs-devel@m.gmane.org; Sun, 15 Jun 2014 05:14:38 +0200 Original-Received: from localhost ([::1]:37435 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ww0tx-0001zY-RT for ged-emacs-devel@m.gmane.org; Sat, 14 Jun 2014 23:14:37 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34360) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ww0tp-0001zO-Fq for emacs-devel@gnu.org; Sat, 14 Jun 2014 23:14:34 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ww0tk-0008A6-8E for emacs-devel@gnu.org; Sat, 14 Jun 2014 23:14:29 -0400 Original-Received: from ironport2-out.teksavvy.com ([206.248.154.181]:46100) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ww0tj-000895-Sm for emacs-devel@gnu.org; Sat, 14 Jun 2014 23:14:24 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ArYGAIDvNVNLd+D9/2dsb2JhbABPCoMGO4MPwD2BFxd0giUBAQEBAgEnLyMFCws0EhQYDSQTCYdoCNIZF44eXAeEOAEDjlSWaINdgWqDTCE X-IPAS-Result: ArYGAIDvNVNLd+D9/2dsb2JhbABPCoMGO4MPwD2BFxd0giUBAQEBAgEnLyMFCws0EhQYDSQTCYdoCNIZF44eXAeEOAEDjlSWaINdgWqDTCE X-IronPort-AV: E=Sophos;i="4.97,753,1389762000"; d="scan'208";a="66892096" Original-Received: from 75-119-224-253.dsl.teksavvy.com (HELO fmsmemgm.homelinux.net) ([75.119.224.253]) by ironport2-out.teksavvy.com with ESMTP/TLS/ADH-AES256-SHA; 14 Jun 2014 23:14:21 -0400 Original-Received: by fmsmemgm.homelinux.net (Postfix, from userid 20848) id AD25FAE0BC; Sat, 14 Jun 2014 23:14:21 -0400 (EDT) In-Reply-To: <53717C7E.60208@siege-engine.com> (Eric M. Ludlam's message of "Mon, 12 May 2014 21:59:26 -0400") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.4.50 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 206.248.154.181 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:172462 gmane.emacs.cedet:6861 Archived-At: > Of course, semantic-ia-complete-symbol calls into other parts of the system > for calculating completions, and I am not familiar enough with the > lexical-binding topic to know if they would be negatively affected or not. > Is there a brief reference I could read about the topic? The issue of lexical-binding is just that it's a feature that was introduced in Emacs-24.1, so code that relies on it won't work in older Emacsen. Anyway, I've since figured that it's simpler to use a new file. Here is my work-in-progress code. I'd welcome comments on it, since I don't know much about Semantic I've had to make a few changes to it (see the overloaded methods I had to change in semantic/analyze.el and semantic/ia.el, meaning that the "overloadability" was moved to a new method) as well as make some assumptions about some of its code (see comment in semantic/analyze/complete.el). Stefan === modified file 'lisp/cedet/semantic.el' --- lisp/cedet/semantic.el 2014-01-01 07:43:34 +0000 +++ lisp/cedet/semantic.el 2014-05-23 02:47:18 +0000 @@ -1155,9 +1157,6 @@ ;; re-activated. (setq semantic-new-buffer-fcn-was-run nil))) -(defun semantic-completion-at-point-function () - 'semantic-ia-complete-symbol) - ;;; Autoload some functions that are not in semantic/loaddefs (autoload 'global-semantic-idle-completions-mode "semantic/idle" === modified file 'lisp/cedet/semantic/analyze.el' --- lisp/cedet/semantic/analyze.el 2014-01-01 07:43:34 +0000 +++ lisp/cedet/semantic/analyze.el 2014-06-15 02:47:17 +0000 @@ -466,32 +466,24 @@ ;; ;; Create a full-up context analysis. ;; + ;;;###autoload -(define-overloadable-function semantic-analyze-current-context (&optional position) - "Analyze the current context at optional POSITION. -If called interactively, display interesting information about POSITION -in a separate buffer. +(define-overloadable-function semantic-analyze-sab-context (sab) + "Analyze the current context at SAB. Returns an object based on symbol `semantic-analyze-context'. +SAB is an object as returned by `semantic-ctxt-current-symbol-and-bounds'. -This function can be overridden with the symbol `analyze-context'. -When overriding this function, your override will be called while -cursor is at POSITION. In addition, your function will not be called -if a cached copy of the return object is found." - (interactive "d") - ;; Only do this in a Semantic enabled buffer. - (when (not (semantic-active-p)) - (error "Cannot analyze buffers not supported by Semantic")) +If a cached copy of the return object is found for symbol `current-context', +it takes precedence." + (cl-assert (semantic-active-p)) ;; Always refresh out tags in a safe way before doing the ;; context. (semantic-refresh-tags-safe) - ;; Do the rest of the analysis. - (if (not position) (setq position (point))) (save-excursion - (goto-char position) - (let* ((answer (semantic-get-cache-data 'current-context))) + (goto-char (car (nth 2 sab))) + (or (semantic-get-cache-data 'current-context) (with-syntax-table semantic-lex-syntax-table - (when (not answer) - (setq answer (:override)) + (let ((answer (:override))) (when (and answer (oref answer bounds)) (with-slots (bounds) answer (semantic-cache-data-to-buffer (current-buffer) @@ -500,27 +492,19 @@ answer 'current-context 'exit-cache-zone))) - ;; Check for interactivity - (when (called-interactively-p 'any) - (if answer - (semantic-analyze-pop-to-context answer) - (message "No Context.")) - )) - - answer)))) + answer))))) -(defun semantic-analyze-current-context-default (position) - "Analyze the current context at POSITION. +(defun semantic-analyze-sab-context-default (sab) + "Analyze the current context SAB. Returns an object based on symbol `semantic-analyze-context'." (let* ((semantic-analyze-error-stack nil) - (context-return nil) - (prefixandbounds (semantic-ctxt-current-symbol-and-bounds (or position (point)))) + (prefixandbounds sab) (prefix (car prefixandbounds)) (bounds (nth 2 prefixandbounds)) ;; @todo - vv too early to really know this answer! vv (prefixclass (semantic-ctxt-current-class-list)) (prefixtypes nil) - (scope (semantic-calculate-scope position)) + (scope (semantic-calculate-scope (car bounds))) (function nil) (fntag nil) arg fntagend argtag @@ -596,6 +580,8 @@ ;; Only do work if we have bounds (meaning a prefix to complete) (when bounds + ;; FIXME: Code duplication! This should use something like + ;; condition-case-unless-debug! (if debug-on-error (catch 'unfindable (setq prefix (semantic-analyze-find-tag-sequence @@ -628,7 +614,6 @@ ;; If we found a tag for our function, we can go into ;; functional context analysis mode, meaning we have a type ;; for the argument. - (setq context-return (semantic-analyze-context-functionarg "functionargument" :buffer (current-buffer) @@ -640,7 +625,7 @@ :prefixclass prefixclass :bounds bounds :prefixtypes prefixtypes - :errors semantic-analyze-error-stack))) + :errors semantic-analyze-error-stack)) ;; No function, try assignment ((and (setq assign (semantic-ctxt-current-assignment)) @@ -651,7 +636,6 @@ (error (semantic-analyze-push-error err) nil))) - (setq context-return (semantic-analyze-context-assignment "assignment" :buffer (current-buffer) @@ -661,7 +645,7 @@ :prefix prefix :prefixclass prefixclass :prefixtypes prefixtypes - :errors semantic-analyze-error-stack))) + :errors semantic-analyze-error-stack)) ;; TODO: Identify return value condition. ;;((setq return .... what to do?) @@ -669,7 +653,6 @@ (bounds ;; Nothing in particular - (setq context-return (semantic-analyze-context "context" :buffer (current-buffer) @@ -678,13 +661,34 @@ :prefix prefix :prefixclass prefixclass :prefixtypes prefixtypes - :errors semantic-analyze-error-stack))) + :errors semantic-analyze-error-stack)) - (t (setq context-return nil)) - ) + (t nil) + ))) - ;; Return our context. - context-return)) +;;;###autoload +(defun semantic-analyze-current-context (&optional position interactive) + "Analyze the current context at optional POSITION. +If called interactively, display interesting information about POSITION +in a separate buffer. +Returns an object based on symbol `semantic-analyze-context'. + +This function can be overridden with the symbol `analyze-context'. +When overriding this function, your override will be called while +cursor is at POSITION. In addition, your function will not be called +if a cached copy of the return object is found." + ;; FIXME: Shouldn't `analyze-context' above be `current-context'? + (interactive "d\np") + ;; Only do this in a Semantic enabled buffer. + (when (not (semantic-active-p)) + (error "Cannot analyze buffers not supported by Semantic")) + (let* ((sab (semantic-ctxt-current-symbol-and-bounds position)) + (answer (when sab (semantic-analyze-sab-context sab)))) + (when interactive + (if answer + (semantic-analyze-pop-to-context answer) + (message "No Context."))) + answer)) (defun semantic-analyze-dereference-alias (taglist) "Dereference first tag in TAGLIST if it is an alias. @@ -742,7 +746,7 @@ :group 'semantic :type semantic-format-tag-custom-list) -(defun semantic-analyze-princ-sequence (sequence &optional prefix buff) +(defun semantic-analyze-princ-sequence (sequence &optional prefix _buff) "Send the tag SEQUENCE to standard out. Use PREFIX as a label. Use BUFF as a source of override methods." @@ -760,8 +764,7 @@ (princ (format "'%S" (car sequence))))) (princ "\n") (setq sequence (cdr sequence)) - (setq prefix (make-string (length prefix) ? )) - )) + (setq prefix (make-string (length prefix) ?\s)))) (defmethod semantic-analyze-show ((context semantic-analyze-context)) "Insert CONTEXT into the current buffer in a nice way." === modified file 'lisp/cedet/semantic/analyze/complete.el' --- lisp/cedet/semantic/analyze/complete.el 2014-01-01 07:43:34 +0000 +++ lisp/cedet/semantic/analyze/complete.el 2014-06-15 03:00:28 +0000 @@ -129,6 +129,14 @@ (do-typeconstraint (not (memq 'no-tc flags))) (do-unique (not (memq 'no-unique flags))) ) + ;; If the buffer text is "p->f_a", this code will only give us the fields + ;; of "p" which start with "f_a". But we may want to complete it to + ;; "p->fastmap_accurate". + ;; In semantic/capf.el we hack around it by fudging `prefix' so it doesn't + ;; exactly contain the buffer text (e.g. it might pretend the user only + ;; typed "p->f" and let the generic completion code take responsibility for + ;; filtering out completions which don't contain the "_a"). + ;; So don't assume that `prefix' really reflects the content of the buffer. ;; Calculate what our prefix string is so that we can ;; find all our matching text. === added file 'lisp/cedet/semantic/capf.el' --- lisp/cedet/semantic/capf.el 1970-01-01 00:00:00 +0000 +++ lisp/cedet/semantic/capf.el 2014-06-15 03:03:44 +0000 @@ -0,0 +1,139 @@ +;;; capf.el --- Completion at point function for Semantic -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Free Software Foundation, Inc. + +;; Author: Stefan Monnier +;; Keywords: + +;; 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 3 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. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(require 'semantic/fw) +(require 'semantic/ia) + +;; FIXME: compared to company-semantic: +;; - we don't distinguish string-or-comment from code. +;; - missing support for :company-docsig, :company-doc-buffer. + +;;;###autoload +(defun semantic-completion-at-point-function () + (when (semantic-active-p) + (let ((sab (semantic-ctxt-current-symbol-and-bounds))) + (when (nth 2 sab) + (let* ((bounds (nth 2 sab)) + (cache (list nil)) + (current (buffer-substring (car bounds) (cdr bounds))) + (table (semantic-capf-completion-table sab cache))) + (when (eq completion-ignore-case + (string= (downcase current) current)) + (setq table + (completion-table-case-fold table completion-ignore-case))) + (list (car (nth 2 sab)) (cdr (nth 2 sab)) table + :exit-function + ;; FIXME: Use lexical-binding! + (lambda (str status) + (when (eq status 'finished) + (let* ((as (semantic-capf-context-and-syms str sab cache)) + (syms (cdr as)) + (tag (semantic-find-first-tag-by-name str syms))) + (when tag + (semantic-ia-completion-completed tag))))) + :company-location + (apply-partially #'semantic-capf-company-location sab cache) + ;; :company-doc-buffer + ;; (apply-partially #'semantic-capf-company-docbuffer sab cache) + ;; :company-docsig + ;; (apply-partially #'semantic-capf-company-docsig sab cache) + )))))) + +(defun semantic-capf-context-and-syms (prefix sab cache) + (unless (and (car cache) + (string-prefix-p (car cache) prefix)) + (let* ((a (if (car cache) (cadr cache) + (semantic-analyze-sab-context sab))) + ;; `sab' and `a' embed the current buffer's "completion text", and + ;; semantic-analyze-possible-completions will compute the completion + ;; of that text, so replace it with the `prefix' which we want to + ;; complete. Otherwise partial or substring completion can't work. + (_ (setf (car (last (oref a prefix))) prefix)) + (syms (semantic-analyze-possible-completions a))) + (setcar cache prefix) + (setcdr cache (cons a syms)))) + (cdr cache)) + + +(defun semantic-capf-completion-table (sab cache) + ;; Calculating completions is a two step process. + ;; + ;; The first analyzes the current context, which finds tags for + ;; all the stuff that may be referenced by the code around POS. + ;; + ;; The second step derives completions from that context. + (let ((buf (current-buffer))) + (completion-table-dynamic + (lambda (pre) + (with-current-buffer buf + ;; FIXME: Figure out how to use completion-boundaries to be able to do + ;; partial completion of "p->f" to "port->fastmap". + (let* ((as (semantic-capf-context-and-syms pre sab cache)) + (a (car as)) + (syms (cdr as))) + ;; Complete this symbol. + (or syms + (if (semantic-analyze-context-p a) + ;; This is a clever hack. If we were unable to find any + ;; smart completions, let's divert to how senator derives + ;; completions. + ;; + ;; This is a way of making this fcn more useful since + ;; the smart completion engine sometimes fails. + (all-completions pre + (semantic--completion-table + buf sab)))))))))) + +(defun semantic-capf-company-location (sab cache str) + (let* ((as (semantic-capf-context-and-syms str sab cache)) + (syms (cdr as)) + (tag (assoc arg syms))) + (when (buffer-live-p (semantic-tag-buffer tag)) + (cons (semantic-tag-buffer tag) + (semantic-tag-start tag))))) + +;; (defun semantic-capf-company-docbuffer (sab cache str) +;; (let* ((as (semantic-capf-context-and-syms str sab cache)) +;; (syms (cdr as)) +;; (tag (assoc arg syms)) +;; (doc (company-semantic-documentation-for-tag tag))) +;; (when doc +;; (with-current-buffer (help-buffer) +;; (help-setup-xref `(semantic-capf-company-docbuffer ,sab ,cache) +;; (company-doc-buffer +;; (concat (funcall semantic-idle-summary-function tag nil t) +;; "\n" +;; doc))))) +;; (when (buffer-live-p (semantic-tag-buffer tag)) +;; (cons (semantic-tag-buffer tag) +;; (semantic-tag-start tag))))) + +;; Local variables: +;; generated-autoload-file: "loaddefs.el" +;; End: + +(provide 'semantic/capf) +;;; capf.el ends here === modified file 'lisp/cedet/semantic/ctxt.el' --- lisp/cedet/semantic/ctxt.el 2014-01-01 07:43:34 +0000 +++ lisp/cedet/semantic/ctxt.el 2014-05-03 15:15:20 +0000 @@ -519,7 +519,7 @@ (error nil))) symlist)))) - +;;;###autoload (define-overloadable-function semantic-ctxt-current-symbol-and-bounds (&optional point) "Return the current symbol and bounds the cursor is on at POINT. The symbol should be the same as returned by `semantic-ctxt-current-symbol'. === modified file 'lisp/cedet/semantic/ia.el' --- lisp/cedet/semantic/ia.el 2014-01-13 20:04:08 +0000 +++ lisp/cedet/semantic/ia.el 2014-06-14 14:39:27 +0000 @@ -68,22 +68,30 @@ ;; character after function names. For Lisp, it might check ;; to put a "(" in front of a function name. -(define-overloadable-function semantic-ia-insert-tag (tag) - "Insert TAG into the current buffer based on completion.") +(define-overloadable-function semantic-ia-completion-completed (tag) + "Add extra text once completion is completed.") -(defun semantic-ia-insert-tag-default (tag) - "Insert TAG into the current buffer based on completion." - (insert (semantic-tag-name tag)) +(defun semantic-ia-completion-completed-default (tag) (let ((tt (semantic-tag-class tag))) - (cond ((eq tt 'function) - (insert "(")) + (cond ((and (eq tt 'function) + (not (looking-at "[ \t]*("))) + ;; FIXME: GNU style (among others) wants a space before the + ;; open paren! + (let ((last-command-event ?\()) + (call-interactively #'self-insert-command))) (t nil)))) +(defun semantic-ia-insert-tag (tag) + (insert (semantic-tag-name tag)) + (semantic-ia-completion-completed tag)) +(make-obsolete 'semantic-ia-insert-tag + 'semantic-ia-completion-completed "24.5") + (defalias 'semantic-ia-get-completions 'semantic-ia-get-completions-deprecated "`Semantic-ia-get-completions' is obsolete. Use `semantic-analyze-possible-completions' instead.") -(defun semantic-ia-get-completions-deprecated (context point) +(defun semantic-ia-get-completions-deprecated (context _point) "A function to help transition away from `semantic-ia-get-completions'. Return completions based on CONTEXT at POINT. You should not use this, nor the aliased version.