]> code.delx.au - gnu-emacs-elpa/commitdiff
Initial import
authorNikolaj Schumacher <git@nschum.de>
Mon, 9 Mar 2009 23:17:42 +0000 (00:17 +0100)
committerNikolaj Schumacher <git@nschum.de>
Mon, 16 Mar 2009 17:04:32 +0000 (18:04 +0100)
.gitignore [new file with mode: 0644]
company.el [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c531d98
--- /dev/null
@@ -0,0 +1 @@
+*.elc
diff --git a/company.el b/company.el
new file mode 100644 (file)
index 0000000..f8bd18e
--- /dev/null
@@ -0,0 +1,271 @@
+(eval-when-compile (require 'cl))
+
+(defgroup company nil
+  ""
+  :group 'abbrev
+  :group 'convenience
+  :group 'maching)
+
+(defface company-tooltip
+  '((t :background "yellow"
+       :foreground "black"))
+  "*"
+  :group 'company)
+
+(defface company-tooltip-selection
+  '((t :background "orange1"
+       :foreground "black"))
+  "*"
+  :group 'company)
+
+(defcustom company-tooltip-limit 10
+  "*"
+  :group 'company
+  :type 'integer)
+
+(defcustom company-backends '(company-elisp-completion)
+  "*"
+  :group 'company
+  :type '(repeat (function :tag "function" nil)))
+
+;;; mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-mode-map
+  (let ((keymap (make-sparse-keymap)))
+    (define-key keymap (kbd "M-n") 'company-select-next)
+    (define-key keymap (kbd "M-p") 'company-select-previous)
+    (define-key keymap (kbd "M-<return>") 'company-complete-selection)
+    keymap))
+
+;;;###autoload
+(define-minor-mode company-mode
+  ""
+  nil " comp" company-mode-map
+  (if company-mode
+      (progn
+        (add-hook 'pre-command-hook 'company-pre-command nil t)
+        (add-hook 'post-command-hook 'company-post-command nil t))
+    (remove-hook 'pre-command-hook 'company-pre-command t)
+    (remove-hook 'post-command-hook 'company-post-command t)
+    (company-cancel)))
+
+;;; backends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-grab (regexp &optional expression)
+  (when (looking-back regexp)
+    (or (match-string-no-properties (or expression 0)) "")))
+
+(defun company-in-string-or-comment (&optional point)
+  (let ((pos (syntax-ppss)))
+    (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
+
+;;; elisp
+
+(defvar company-lisp-symbol-regexp
+  "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
+
+(defun company-grab-lisp-symbol ()
+  (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
+    (unless (and (company-in-string-or-comment (- (point) (length prefix)))
+                 (/= (char-before (- (point) (length prefix))) ?`))
+      prefix)))
+
+(defun company-elisp-completion (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'emacs-lisp-mode)
+                  (company-grab-lisp-symbol)))
+    ('candidates (let ((completion-ignore-case nil))
+                   (all-completions arg obarray
+                                    (lambda (symbol) (or (boundp symbol)
+                                                         (fboundp symbol))))))))
+
+;;; completion mechanism ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-backend nil)
+(make-variable-buffer-local 'company-backend)
+
+(defvar company-prefix nil)
+(make-variable-buffer-local 'company-prefix)
+
+(defvar company-candidates nil)
+(make-variable-buffer-local 'company-candidates)
+
+(defvar company-selection 0)
+(make-variable-buffer-local 'company-selection)
+
+(defvar company-point nil)
+(make-variable-buffer-local 'company-point)
+
+(defsubst company-strip-prefix (str)
+  (substring str (length company-prefix)))
+
+(defun company-begin ()
+  (let ((completion-ignore-case nil) ;; TODO: make this optional
+        prefix)
+    (dolist (backend company-backends)
+      (when (setq prefix (funcall backend 'prefix))
+        (setq company-backend backend
+              company-prefix prefix
+              company-candidates
+              (funcall company-backend 'candidates prefix)
+              company-selection 0
+              company-point (point))
+        (return prefix)))
+    (unless (or (cdr company-candidates)
+                (when company-candidates
+                  (not (equal (car company-candidates) company-prefix))))
+      (company-cancel))))
+
+(defun company-cancel ()
+  (setq company-backend nil
+        company-prefix nil
+        company-candidates nil
+        company-selection 0
+        company-point nil)
+  (company-pseudo-tooltip-hide))
+
+(defun company-pre-command ()
+  (company-pseudo-tooltip-hide))
+
+(defun company-post-command ()
+  (unless (equal (point) company-point)
+    (company-begin))
+  (when company-candidates
+    (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
+                                          company-candidates
+                                          company-selection)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-select-next ()
+  (interactive)
+  (setq company-selection (min (1- (length company-candidates))
+                               (1+ company-selection))))
+
+(defun company-select-previous ()
+  (interactive)
+  (setq company-selection (max 0 (1- company-selection))))
+
+(defun company-complete-selection ()
+  (interactive)
+  (insert (company-strip-prefix (nth company-selection company-candidates))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst company-space-strings-limit 100)
+
+(defconst company-space-strings
+  (let (lst)
+    (dotimes (i company-space-strings-limit)
+      (push (make-string (- company-space-strings-limit 1 i) ?\  ) lst))
+    (apply 'vector lst)))
+
+(defsubst company-space-string (len)
+  (if (< len company-space-strings-limit)
+      (aref company-space-strings len)
+    (make-string len ?\ )))
+
+(defsubst company-safe-substring (str from &optional to)
+  (let ((len (length str)))
+    (if (> from len)
+        ""
+      (if (and to (> to len))
+          (concat (substring str from)
+                  (company-space-string (- to len)))
+        (substring str from to)))))
+
+;;; pseudo-tooltip ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-pseudo-tooltip-overlay nil)
+(make-variable-buffer-local 'company-pseudo-tooltip-overlay)
+
+;;; propertize
+
+(defun company-fill-propertize (line width face)
+  (setq line (company-safe-substring line 0 width))
+  (add-text-properties 0 width (list 'face face) line)
+  line)
+
+(defun company-fill-propertize-lines (column lines selection)
+  (let ((width 0)
+        (lines-copy lines)
+        (len (min company-tooltip-limit (length lines)))
+        new)
+    (dotimes (i len)
+      (setq width (max (length (pop lines-copy)) width)))
+    (setq width (min width (- (window-width) column)))
+    (dotimes (i len)
+      (push (company-fill-propertize (pop lines) width
+                                     (if (equal i selection)
+                                         'company-tooltip-selection
+                                       'company-tooltip))
+            new))
+    (nreverse new)))
+
+;;; replace
+
+(defun company-buffer-lines (beg end)
+  (goto-char beg)
+  (let ((row (cdr (posn-col-row (posn-at-point))))
+        lines)
+    (while (< (point) end)
+      (move-to-window-line (incf row))
+      (push (buffer-substring beg (min end (1- (point)))) lines)
+      (setq beg (point)))
+    (nreverse lines)))
+
+(defun company-modify-line (old new offset)
+  (concat (company-safe-substring old 0 offset)
+          new
+          (company-safe-substring old (+ offset (length new)))))
+
+(defun company-modified-substring (beg end lines column)
+  (let ((old (company-buffer-lines beg end))
+        new)
+    ;; Inject into old lines.
+    (while old
+      (push (company-modify-line (pop old) (pop lines) column) new))
+    ;; Append whole new lines.
+    (while lines
+      (push (company-modify-line "" (pop lines) column) new))
+    (concat (mapconcat 'identity (nreverse new) "\n")
+            "\n")))
+
+;; show
+
+(defun company-pseudo-tooltip-show (row column lines &optional selection)
+  (company-pseudo-tooltip-hide)
+  (unless lines (error "No text provided"))
+  (save-excursion
+
+    (setq lines (company-fill-propertize-lines column lines selection))
+
+
+    (move-to-column 0)
+    (move-to-window-line row)
+    (let ((beg (point))
+          (end (save-excursion
+                 (move-to-window-line (min (window-height)
+                                           (+ row company-tooltip-limit)))
+                 (point)))
+          str)
+
+      (setq company-pseudo-tooltip-overlay (make-overlay beg end))
+
+      (overlay-put company-pseudo-tooltip-overlay 'before-string
+                   (company-modified-substring beg end lines column))
+      (overlay-put company-pseudo-tooltip-overlay 'invisible t)
+      (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
+
+(defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
+  (let ((col-row (posn-col-row (posn-at-point pos))))
+    (company-pseudo-tooltip-show (1+ (cdr col-row))
+                                 (car col-row) text selection)))
+
+(defun company-pseudo-tooltip-hide ()
+  (when company-pseudo-tooltip-overlay
+    (delete-overlay company-pseudo-tooltip-overlay)
+    (setq company-pseudo-tooltip-overlay nil)))
+
+(provide 'company)
+;;; company.el ends here