2014-09-04 22:46:41 +00:00
|
|
|
;; -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
|
|
;; Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
;;
|
|
|
|
;; Author: Soonho Kong
|
|
|
|
;;
|
2014-08-26 16:26:29 +00:00
|
|
|
(require 'company)
|
2014-09-04 22:46:41 +00:00
|
|
|
(require 'company-etags)
|
|
|
|
(require 'dash)
|
|
|
|
(require 'dash-functional)
|
2014-09-14 07:00:25 +00:00
|
|
|
(require 'f)
|
2014-09-26 06:53:06 +00:00
|
|
|
(require 's)
|
2015-02-13 17:19:25 +00:00
|
|
|
(require 'lean-util)
|
2014-09-04 22:46:41 +00:00
|
|
|
(require 'lean-tags)
|
|
|
|
(require 'lean-server)
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-04 22:46:41 +00:00
|
|
|
(defun company-lean-hook ()
|
2014-09-14 07:00:25 +00:00
|
|
|
(set (make-local-variable 'company-backends) '(company-lean--import
|
2014-09-29 18:09:49 +00:00
|
|
|
company-lean--option-name
|
2014-09-14 07:00:25 +00:00
|
|
|
company-lean--findg
|
|
|
|
company-lean--findp))
|
2014-09-04 22:46:41 +00:00
|
|
|
(setq-local company-tooltip-limit 20) ; bigger popup window
|
2014-09-14 07:00:25 +00:00
|
|
|
(setq-local company-idle-delay nil) ; decrease delay before autocompletion popup shows
|
2014-09-04 22:46:41 +00:00
|
|
|
(setq-local company-echo-delay 0) ; remove annoying blinking
|
|
|
|
(setq-local company-begin-commands '(self-insert-command)) ; start autocompletion only after typing
|
|
|
|
(company-mode t))
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-15 06:07:17 +00:00
|
|
|
(defun company-lean--check-prefix ()
|
|
|
|
"Check whether to use company-lean or not"
|
|
|
|
(or (company-lean--import-prefix)
|
2014-09-29 18:09:49 +00:00
|
|
|
(company-lean--option-name-prefix)
|
2014-09-15 06:07:17 +00:00
|
|
|
(company-lean--findg-prefix)
|
|
|
|
(company-lean--findp-prefix)))
|
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
(defun company-lean--import-remove-lean (file-name)
|
|
|
|
(cond
|
|
|
|
((s-ends-with? "/default.lean" file-name)
|
|
|
|
(s-left (- (length file-name)
|
|
|
|
(length "/default.lean"))
|
|
|
|
file-name))
|
2014-12-05 21:09:23 +00:00
|
|
|
((s-ends-with? "/default.hlean" file-name)
|
|
|
|
(s-left (- (length file-name)
|
|
|
|
(length "/default.hlean"))
|
|
|
|
file-name))
|
2014-09-14 07:00:25 +00:00
|
|
|
((s-ends-with? ".lean" file-name)
|
|
|
|
(s-left (- (length file-name)
|
|
|
|
(length ".lean"))
|
|
|
|
file-name))
|
2014-12-05 21:09:23 +00:00
|
|
|
((s-ends-with? ".hlean" file-name)
|
|
|
|
(s-left (- (length file-name)
|
|
|
|
(length ".hlean"))
|
|
|
|
file-name))
|
2014-09-14 07:00:25 +00:00
|
|
|
(t file-name)))
|
|
|
|
|
2014-09-15 05:58:49 +00:00
|
|
|
(defun company-lean--import-candidates-main (root-dir)
|
|
|
|
(when root-dir
|
2015-02-13 17:19:25 +00:00
|
|
|
(let* ((target-ext (pcase (lean-choose-minor-mode-based-on-extension)
|
|
|
|
(`hott "hlean")
|
|
|
|
(`standard "lean")))
|
|
|
|
(lean-files (f-files root-dir
|
|
|
|
(lambda (file) (equal (f-ext file) target-ext))
|
2014-09-15 05:58:49 +00:00
|
|
|
t))
|
|
|
|
;; Relative to project root-dir
|
|
|
|
(lean-files-r (--map (f-relative it root-dir) lean-files))
|
|
|
|
(candidates
|
|
|
|
(--map (s-replace-all `((,(f-path-separator) . "."))
|
|
|
|
(company-lean--import-remove-lean it))
|
|
|
|
lean-files-r)))
|
|
|
|
(--zip-with (propertize it 'file-name other) candidates lean-files))))
|
2014-09-14 07:00:25 +00:00
|
|
|
|
|
|
|
(defun company-lean--import-prefix ()
|
2014-09-29 18:09:49 +00:00
|
|
|
"Import auto-completion is triggered when it looks at 'import ...'"
|
2014-09-14 07:00:25 +00:00
|
|
|
(when (looking-back
|
|
|
|
(rx "import"
|
|
|
|
(* (+ white)
|
|
|
|
(+ (or alnum digit "." "_")))
|
|
|
|
(? (+ white))))
|
|
|
|
(company-grab-symbol)))
|
|
|
|
|
|
|
|
(defun company-lean--import-candidates (prefix)
|
|
|
|
(let* ((cur-dir (f-dirname (buffer-file-name)))
|
|
|
|
(parent-dir (f-parent cur-dir))
|
2014-09-15 05:58:49 +00:00
|
|
|
(project-dir (f--traverse-upwards (f-exists? (f-expand ".project" it))
|
|
|
|
(f-dirname (buffer-file-name))))
|
2014-09-14 07:00:25 +00:00
|
|
|
(candidates
|
|
|
|
(cond
|
|
|
|
;; prefix = ".."
|
|
|
|
((and parent-dir (s-starts-with? ".." prefix))
|
|
|
|
(--map (concat ".." it)
|
|
|
|
(company-lean--import-candidates-main parent-dir)))
|
|
|
|
;; prefix = "."
|
|
|
|
((s-starts-with? "." prefix)
|
|
|
|
(--map (concat "." it)
|
|
|
|
(company-lean--import-candidates-main cur-dir)))
|
2014-09-15 05:58:49 +00:00
|
|
|
;; normal prefix
|
|
|
|
(t (-flatten
|
|
|
|
(-map 'company-lean--import-candidates-main
|
|
|
|
(lean-path-list)))))))
|
2014-09-14 07:00:25 +00:00
|
|
|
(--filter (s-starts-with? prefix it) candidates)))
|
|
|
|
|
|
|
|
(defun company-lean--import-location (arg)
|
|
|
|
(let ((file-name (get-text-property 0 'file-name arg)))
|
|
|
|
`(,file-name . 1)))
|
|
|
|
|
|
|
|
(defun company-lean--import (command &optional arg &rest ignored)
|
|
|
|
(case command
|
|
|
|
(prefix (company-lean--import-prefix))
|
|
|
|
(candidates (company-lean--import-candidates arg))
|
|
|
|
(location (company-lean--import-location arg))
|
|
|
|
(sorted t)))
|
|
|
|
|
2014-09-29 18:09:49 +00:00
|
|
|
;; OPTION
|
|
|
|
;; ======
|
|
|
|
(defun company-lean--option-name-prefix ()
|
|
|
|
"Option auto-completion is triggered when it looks at 'set-option '"
|
|
|
|
(when (looking-back (rx "set_option" (+ white) (* (or alnum digit "." "_"))))
|
|
|
|
(company-grab-symbol)))
|
|
|
|
|
|
|
|
(defun company-lean--option-name-candidates (prefix)
|
|
|
|
(let ((candidates
|
|
|
|
(lean-get-options-sync-with-cont
|
|
|
|
(lambda (option-record-alist)
|
|
|
|
(-map 'car option-record-alist)))))
|
|
|
|
(--filter (s-starts-with? prefix it) candidates)))
|
|
|
|
|
|
|
|
(defun company-lean--option-name (command &optional arg &rest ignored)
|
|
|
|
(case command
|
|
|
|
(prefix (company-lean--option-name-prefix))
|
|
|
|
(candidates (company-lean--option-name-candidates arg))
|
|
|
|
(sorted t)))
|
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
;; FINDG
|
|
|
|
;; =====
|
|
|
|
|
|
|
|
(defun company-lean--findg-prefix ()
|
|
|
|
"FINDG is triggered when it looks at '_'"
|
|
|
|
(when (looking-at (rx symbol-start "_")) ""))
|
|
|
|
|
|
|
|
(defun company-lean--findg-candidates (prefix)
|
|
|
|
(let ((line-number (line-number-at-pos))
|
2014-10-07 21:40:54 +00:00
|
|
|
(column-number (lean-line-offset))
|
2014-09-14 07:00:25 +00:00
|
|
|
pattern)
|
|
|
|
(lean-server-send-cmd-sync (lean-cmd-wait) '(lambda () ()))
|
|
|
|
(setq pattern (if current-prefix-arg
|
|
|
|
(read-string "Filter for find declarations (e.g: +intro -and): " "" nil "")
|
|
|
|
""))
|
|
|
|
(lean-server-send-cmd-sync (lean-cmd-findg line-number column-number pattern)
|
|
|
|
(lambda (candidates)
|
|
|
|
(lean-debug "executing continuation for FINDG")
|
2014-09-15 05:59:48 +00:00
|
|
|
(--map (company-lean--findp-make-candidate it prefix) candidates)))))
|
2014-09-14 07:00:25 +00:00
|
|
|
|
|
|
|
(defun company-lean--findg-pre-completion (args)
|
|
|
|
"Delete current '_' before filling the selected AC candidate"
|
|
|
|
(when (looking-at (rx "_"))
|
|
|
|
(delete-forward-char 1)))
|
|
|
|
|
|
|
|
(defun company-lean--findg (command &optional arg &rest ignored)
|
|
|
|
(case command
|
|
|
|
(prefix (company-lean--findg-prefix))
|
|
|
|
(candidates (company-lean--findg-candidates arg))
|
|
|
|
(annotation (company-lean--findp-annotation arg))
|
|
|
|
(location (company-lean--findp-location arg))
|
|
|
|
(pre-completion (company-lean--findg-pre-completion arg))
|
|
|
|
(sorted t)))
|
|
|
|
|
|
|
|
;; FINDP
|
|
|
|
;; -----
|
2014-09-08 00:29:51 +00:00
|
|
|
(defun company-lean--need-autocomplete ()
|
2014-09-29 18:09:49 +00:00
|
|
|
(interactive)
|
|
|
|
(cond ((looking-back
|
|
|
|
(rx (or "theorem" "definition" "lemma" "axiom" "parameter"
|
|
|
|
"variable" "hypothesis" "conjecture"
|
|
|
|
"corollary" "open")
|
|
|
|
(+ white)
|
|
|
|
(* (not white))))
|
|
|
|
nil)
|
|
|
|
((looking-back (rx "set_option"
|
|
|
|
(+ white)
|
|
|
|
(+ (or alnum digit "." "_"))
|
|
|
|
(+ white)
|
|
|
|
(* (or alnum digit "." "_"))))
|
|
|
|
nil)
|
|
|
|
(t t)))
|
2014-09-08 00:29:51 +00:00
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
(defun company-lean--findp-prefix ()
|
2014-08-26 16:26:29 +00:00
|
|
|
"Returns the symbol to complete. Also, if point is on a dot,
|
|
|
|
triggers a completion immediately."
|
2014-10-01 16:52:37 +00:00
|
|
|
(let ((prefix (lean-grab-hname)))
|
2014-09-14 07:00:25 +00:00
|
|
|
(when (and
|
|
|
|
prefix
|
|
|
|
(company-lean--need-autocomplete)
|
|
|
|
(or
|
|
|
|
(>= (length prefix) 1)
|
|
|
|
(string-match "[_.]" prefix)))
|
2014-09-26 06:53:06 +00:00
|
|
|
(when (s-starts-with? "@" prefix)
|
|
|
|
(setq prefix (substring prefix 1)))
|
2014-09-14 07:00:25 +00:00
|
|
|
prefix)))
|
|
|
|
|
2014-09-15 05:59:48 +00:00
|
|
|
(defun company-lean--findp-make-candidate (arg prefix)
|
|
|
|
(let* ((text (car arg))
|
|
|
|
(type (cdr arg))
|
|
|
|
(start (s-index-of prefix text)))
|
|
|
|
(propertize text
|
|
|
|
'type type
|
|
|
|
'start start
|
|
|
|
'prefix prefix)))
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-30 00:01:42 +00:00
|
|
|
(defun company-lean--handle-singleton-candidate (prefix candidates)
|
|
|
|
"Handle singleton candidate. If the candidate does not start
|
|
|
|
with prefix, we add prefix itself as a candidate to prevent
|
|
|
|
from auto-completion."
|
|
|
|
(let ((candidate (car candidates)))
|
|
|
|
(cond ((s-prefix? prefix candidate) candidates)
|
|
|
|
(t `(,candidate ,prefix)))))
|
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
(defun company-lean--findp-candidates (prefix)
|
2014-09-08 23:03:44 +00:00
|
|
|
(let ((line-number (line-number-at-pos))
|
|
|
|
pattern)
|
2014-09-11 20:46:07 +00:00
|
|
|
(lean-server-send-cmd-sync (lean-cmd-wait) '(lambda () ()))
|
2014-09-14 07:00:25 +00:00
|
|
|
(lean-server-send-cmd-sync (lean-cmd-findp line-number prefix)
|
|
|
|
(lambda (candidates)
|
|
|
|
(lean-debug "executing continuation for FINDP")
|
2014-09-30 00:01:42 +00:00
|
|
|
(setq candidates
|
|
|
|
(--map (company-lean--findp-make-candidate it prefix)
|
|
|
|
candidates))
|
|
|
|
(when (= (length candidates) 1)
|
|
|
|
(setq candidates
|
|
|
|
(company-lean--handle-singleton-candidate prefix candidates)))
|
|
|
|
candidates))))
|
2014-09-14 07:00:25 +00:00
|
|
|
|
|
|
|
(defun company-lean--findp-location (arg)
|
2014-09-04 22:46:41 +00:00
|
|
|
(lean-generate-tags)
|
|
|
|
(let ((tags-table-list (company-etags-buffer-table)))
|
|
|
|
(when (fboundp 'find-tag-noselect)
|
|
|
|
(save-excursion
|
|
|
|
(let ((buffer (find-tag-noselect arg)))
|
|
|
|
(cons buffer (with-current-buffer buffer (point))))))))
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
(defun company-lean--findp-annotation (candidate)
|
2014-09-04 22:46:41 +00:00
|
|
|
(let ((type (get-text-property 0 'type candidate)))
|
|
|
|
(when type
|
2014-09-05 13:51:05 +00:00
|
|
|
(let* ((annotation-str (format " : %s" type))
|
|
|
|
(annotation-len (length annotation-str))
|
|
|
|
(candidate-len (length candidate))
|
|
|
|
(entry-width (+ candidate-len
|
|
|
|
annotation-len))
|
2014-09-05 15:46:58 +00:00
|
|
|
(allowed-width (truncate (* 0.90 (window-body-width)))))
|
|
|
|
(when (> entry-width allowed-width)
|
2014-09-05 13:51:05 +00:00
|
|
|
(setq annotation-str
|
2014-09-05 15:46:58 +00:00
|
|
|
(concat
|
|
|
|
(substring-no-properties annotation-str
|
2014-09-05 13:51:05 +00:00
|
|
|
0
|
2014-09-05 15:46:58 +00:00
|
|
|
(- allowed-width candidate-len 3))
|
|
|
|
"...")))
|
2014-09-05 13:51:05 +00:00
|
|
|
annotation-str))))
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-15 05:59:48 +00:00
|
|
|
(defun company-lean--findp-match (arg)
|
|
|
|
"Return the end of matched region"
|
|
|
|
(let ((prefix (get-text-property 0 'prefix arg))
|
|
|
|
(start (get-text-property 0 'start arg)))
|
|
|
|
(if start
|
|
|
|
(+ start (length prefix))
|
|
|
|
0)))
|
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
(defun company-lean--findp (command &optional arg &rest ignored)
|
2014-08-26 16:26:29 +00:00
|
|
|
(case command
|
2014-09-14 07:00:25 +00:00
|
|
|
(prefix (company-lean--findp-prefix))
|
|
|
|
(candidates (company-lean--findp-candidates arg))
|
|
|
|
(annotation (company-lean--findp-annotation arg))
|
|
|
|
(location (company-lean--findp-location arg))
|
2014-09-15 05:59:48 +00:00
|
|
|
(match (company-lean--findp-match arg))
|
|
|
|
(no-cache t)
|
2014-09-29 17:31:59 +00:00
|
|
|
(require-match 'never)
|
2014-09-04 22:46:41 +00:00
|
|
|
(sorted t)))
|
2014-08-26 16:26:29 +00:00
|
|
|
|
2014-09-14 07:00:25 +00:00
|
|
|
;; ADVICES
|
|
|
|
;; =======
|
|
|
|
|
2014-09-06 06:06:02 +00:00
|
|
|
(defadvice company--window-width
|
2014-09-08 16:45:47 +00:00
|
|
|
(after lean-company--window-width activate)
|
2014-09-06 06:06:02 +00:00
|
|
|
(when (eq major-mode 'lean-mode)
|
|
|
|
(setq ad-return-value (truncate (* 0.95 (window-body-width))))))
|
|
|
|
|
2014-09-08 16:45:47 +00:00
|
|
|
(defun replace-regex-return-position (regex rep string &optional start)
|
|
|
|
"Find regex and replace with rep on string.
|
|
|
|
|
|
|
|
Return replaced string and start and end positions of replacement."
|
|
|
|
(let* ((start (or start 0))
|
|
|
|
(len (length string))
|
|
|
|
(m-start (string-match regex string start))
|
|
|
|
(m-end (match-end 0))
|
|
|
|
pre-string post-string matched-string replaced-string result)
|
|
|
|
(cond (m-start
|
|
|
|
(setq pre-string (substring string 0 m-start))
|
|
|
|
(setq matched-string (substring string m-start m-end))
|
|
|
|
(setq post-string (substring string m-end))
|
|
|
|
(string-match regex matched-string)
|
|
|
|
(setq replaced-string
|
|
|
|
(replace-match rep nil nil matched-string))
|
|
|
|
(setq result (concat pre-string
|
|
|
|
replaced-string
|
|
|
|
post-string))
|
|
|
|
`(,result ,m-start ,(+ m-start (length replaced-string)))
|
|
|
|
))))
|
|
|
|
|
|
|
|
(defun replace-regex-add-properties-all (regex rep string properties)
|
|
|
|
"Find all occurrences of regex in string, and replace them with
|
|
|
|
rep. Then, add text-properties on the replaced region."
|
|
|
|
(let ((replace-result-items (replace-regex-return-position regex rep string))
|
|
|
|
(result string))
|
|
|
|
(while replace-result-items
|
|
|
|
(pcase replace-result-items
|
|
|
|
(`(,replaced-string ,m-start ,m-end)
|
|
|
|
(setq result replaced-string)
|
|
|
|
(add-text-properties m-start m-end properties result)
|
|
|
|
(setq replace-result-items
|
|
|
|
(replace-regex-return-position regex rep result m-end)))))
|
|
|
|
result))
|
|
|
|
|
2014-09-11 20:38:29 +00:00
|
|
|
(eval-after-load 'company
|
|
|
|
'(defadvice company-fill-propertize
|
|
|
|
(after lean-company-fill-propertize activate)
|
|
|
|
(when (eq major-mode 'lean-mode)
|
|
|
|
(let* ((selected (ad-get-arg 3))
|
2014-09-15 03:41:45 +00:00
|
|
|
(foreground-color lean-company-type-foreground)
|
2014-09-11 20:38:29 +00:00
|
|
|
(background-color (if selected (face-background 'company-tooltip-selection)
|
|
|
|
(face-background 'company-tooltip)))
|
|
|
|
(face-attrs
|
|
|
|
(cond (background-color `(:foreground ,foreground-color
|
|
|
|
:background ,background-color))
|
|
|
|
(t `(:foreground ,foreground-color))))
|
|
|
|
(properties `(face ,face-attrs
|
|
|
|
mouse-face company-tooltip))
|
|
|
|
(old-return ad-return-value)
|
|
|
|
(old-len (length old-return))
|
|
|
|
new-return new-len)
|
|
|
|
(setq new-return
|
|
|
|
(replace-regex-add-properties-all
|
|
|
|
(rx "?" word-start (group (+ (not white))) word-end)
|
|
|
|
"\\1"
|
|
|
|
ad-return-value
|
|
|
|
properties))
|
|
|
|
(setq new-len (length new-return))
|
|
|
|
(while (< (length new-return) old-len)
|
|
|
|
(setq new-return
|
|
|
|
(concat new-return " ")))
|
|
|
|
(when background-color
|
|
|
|
(add-text-properties new-len old-len properties new-return))
|
|
|
|
(setq ad-return-value new-return)))))
|
2014-09-09 20:20:22 +00:00
|
|
|
|
2014-09-04 22:46:41 +00:00
|
|
|
(provide 'lean-company)
|