Skip to content

Commit 60ded1b

Browse files
ultronozmbbatsov
authored andcommitted
Replace manual change tracking with track-changes library
* copilot.el (track-changes): New requirement. (copilot--lsp-pos): New helper function. (copilot--generate-doc): Use it. (copilot--on-doc-change): Remove. (copilot--track-changes-id): New buffer-local variable. (copilot--lsp-range-end-from-oldtext): New helper function. (copilot--track-changes-signal): New function to fetch and forward buffer changes. (copilot--mode-setup): Remove old before-change-functions and after-change-functions hooks, register with track-changes instead. (copilot--mode-teardown): Remove old cleanup code, unregister from track-changes. * Eask: Add track-changes version 1.4 as a dependency.
1 parent 6a2ad80 commit 60ded1b

File tree

2 files changed

+72
-34
lines changed

2 files changed

+72
-34
lines changed

Eask

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
(depends-on "editorconfig")
1919
(depends-on "jsonrpc")
2020
(depends-on "f")
21+
(depends-on "track-changes" "1.4")
2122

2223
(setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432

copilot.el

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
;; Rakotomandimby Mihamina <[email protected]>
99
;; Bozhidar Batsov <[email protected]>
1010
;; URL: https://github.com/copilot-emacs/copilot.el
11-
;; Package-Requires: ((emacs "27.2") (editorconfig "0.8.2") (jsonrpc "1.0.14") (f "0.20.0"))
11+
;; Package-Requires: ((emacs "27.2") (editorconfig "0.8.2") (jsonrpc "1.0.14") (f "0.20.0") (track-changes "1.4"))
1212
;; Version: 0.3.0-snapshot
1313
;; Keywords: convenience copilot
1414

@@ -48,6 +48,7 @@
4848
(require 'editorconfig)
4949

5050
(require 'copilot-balancer)
51+
(require 'track-changes)
5152

5253
(defgroup copilot nil
5354
"Copilot."
@@ -705,6 +706,14 @@ automatically, browse to %s." user-code verification-uri))
705706
(or (copilot--get-minor-mode-language-id)
706707
(copilot--get-major-mode-language-id)))
707708

709+
(defun copilot--lsp-pos (&optional pos)
710+
"Return an LSP position plist for buffer POS.
711+
POS defaults to point."
712+
(save-excursion
713+
(when pos (goto-char pos))
714+
(list :line (- (line-number-at-pos) copilot--line-bias)
715+
:character (- (point) (line-beginning-position)))))
716+
708717
(defun copilot--generate-doc ()
709718
"Generate doc parameters for completion request."
710719
(save-restriction
@@ -719,8 +728,7 @@ automatically, browse to %s." user-code verification-uri))
719728
:uri (copilot--get-uri)
720729
:relativePath (copilot--get-relative-path)
721730
:languageId (copilot--get-language-id)
722-
:position (list :line (- (line-number-at-pos) copilot--line-bias)
723-
:character (- (point) (line-beginning-position))))))
731+
:position (copilot--lsp-pos))))
724732

725733
(defun copilot--get-completion (callback)
726734
"Get completion with CALLBACK."
@@ -1077,40 +1085,13 @@ provided."
10771085
:version copilot--doc-version
10781086
:text (copilot--get-source)))))))
10791087

1080-
(defun copilot--on-doc-change (&optional beg end chars-replaced)
1081-
"Notify that the document has changed.
1082-
1083-
Arguments BEG, END, and CHARS-REPLACED are metadata for region changed."
1084-
(let* ((is-before-change (null chars-replaced))
1085-
(is-after-change (not is-before-change))
1086-
;; for a deletion, the post-change beginning and end are at the same place.
1087-
(is-insertion (and is-after-change (not (equal beg end))))
1088-
(is-deletion (and is-before-change (not (equal beg end)))))
1089-
(when (or is-insertion is-deletion)
1090-
(save-restriction
1091-
(save-match-data
1092-
(widen)
1093-
(let* ((range-start (list :line (- (line-number-at-pos beg) copilot--line-bias)
1094-
:character (- beg (save-excursion (goto-char beg) (line-beginning-position)))))
1095-
(range-end (if is-insertion range-start
1096-
(list :line (- (line-number-at-pos end) copilot--line-bias)
1097-
:character (- end (save-excursion (goto-char end) (line-beginning-position))))))
1098-
(text (if is-insertion (buffer-substring-no-properties beg end) ""))
1099-
(content-changes (vector (list :range (list :start range-start :end range-end)
1100-
:text text))))
1101-
(cl-incf copilot--doc-version)
1102-
(copilot--notify 'textDocument/didChange
1103-
(list :textDocument (list :uri (copilot--get-uri) :version copilot--doc-version)
1104-
:contentChanges content-changes))))))))
1105-
11061088
(defun copilot--on-doc-close (&rest _args)
11071089
"Notify that the document has been closed."
11081090
(when (seq-contains-p copilot--opened-buffers (current-buffer))
11091091
(copilot--notify 'textDocument/didClose
11101092
(list :textDocument (list :uri (copilot--get-uri))))
11111093
(setq copilot--opened-buffers (delete (current-buffer) copilot--opened-buffers))))
11121094

1113-
11141095
;;;###autoload
11151096
(defun copilot-complete ()
11161097
"Complete at the current point."
@@ -1129,6 +1110,60 @@ Arguments BEG, END, and CHARS-REPLACED are metadata for region changed."
11291110
(when called-interactively
11301111
(copilot--log 'warning "No completion is available."))))))))
11311112

1113+
;;
1114+
;; integration with track-changes
1115+
;;
1116+
1117+
(defvar-local copilot--track-changes-id nil
1118+
"Tracker id from `track-changes-register' for this buffer.")
1119+
1120+
(defun copilot--lsp-range-end-from-oldtext (beg oldtext)
1121+
"Compute old end position plist for change at BEG replacing OLDTEXT."
1122+
(if (string-empty-p oldtext)
1123+
;; Optimization for pure insertions
1124+
(copilot--lsp-pos beg)
1125+
(let* ((start (copilot--lsp-pos beg))
1126+
(start-line (plist-get start :line))
1127+
(start-char (plist-get start :character))
1128+
(end-info (with-temp-buffer
1129+
(insert oldtext)
1130+
(goto-char (point-max))
1131+
(cons (1- (line-number-at-pos))
1132+
(current-column))))
1133+
(num-newlines (car end-info))
1134+
(end-char (cdr end-info)))
1135+
(list :line (+ start-line num-newlines)
1136+
:character (if (= num-newlines 0)
1137+
(+ start-char (length oldtext))
1138+
end-char)))))
1139+
1140+
(defun copilot--track-changes-signal (id &optional _distance)
1141+
"Handle track changes signal for given tracker ID.
1142+
Fetch changes and notify the language server."
1143+
(condition-case err
1144+
(save-restriction
1145+
(widen)
1146+
(track-changes-fetch
1147+
id
1148+
(lambda (beg end before)
1149+
(unless (eq before 'error)
1150+
(save-restriction
1151+
(widen)
1152+
(let* ((new-text (buffer-substring-no-properties beg end))
1153+
(start-pos (copilot--lsp-pos beg))
1154+
(end-pos (copilot--lsp-range-end-from-oldtext beg (or before ""))))
1155+
(cl-incf copilot--doc-version)
1156+
(copilot--notify
1157+
'textDocument/didChange
1158+
(list :textDocument (list :uri (copilot--get-uri)
1159+
:version copilot--doc-version)
1160+
:contentChanges
1161+
(vector
1162+
(list :range (list :start start-pos :end end-pos)
1163+
:text new-text))))))))))
1164+
(error
1165+
(copilot--log 'error "Change fetch failed: %s" (error-message-string err)))))
1166+
11321167
;;
11331168
;; minor mode
11341169
;;
@@ -1249,24 +1284,26 @@ Use this for custom bindings in `copilot-mode'.")
12491284
(defun copilot--mode-setup ()
12501285
"Set up copilot mode."
12511286
(add-hook 'post-command-hook #'copilot--post-command nil 'local)
1252-
(add-hook 'before-change-functions #'copilot--on-doc-change nil 'local)
1253-
(add-hook 'after-change-functions #'copilot--on-doc-change nil 'local)
12541287
;; Hook onto both window-selection-change-functions and window-buffer-change-functions
12551288
;; since both are separate ways of 'focussing' a buffer.
12561289
(add-hook 'window-selection-change-functions #'copilot--on-doc-focus nil 'local)
12571290
(add-hook 'window-buffer-change-functions #'copilot--on-doc-focus nil 'local)
12581291
(add-hook 'kill-buffer-hook #'copilot--on-doc-close nil 'local)
1292+
(unless copilot--track-changes-id
1293+
(setq copilot--track-changes-id
1294+
(track-changes-register #'copilot--track-changes-signal)))
12591295
;; The mode may be activated manually while focus remains on the current window/buffer.
12601296
(copilot--on-doc-focus (selected-window)))
12611297

12621298
(defun copilot--mode-teardown ()
12631299
"Tear down copilot mode."
12641300
(remove-hook 'post-command-hook #'copilot--post-command 'local)
1265-
(remove-hook 'before-change-functions #'copilot--on-doc-change 'local)
1266-
(remove-hook 'after-change-functions #'copilot--on-doc-change 'local)
12671301
(remove-hook 'window-selection-change-functions #'copilot--on-doc-focus 'local)
12681302
(remove-hook 'window-buffer-change-functions #'copilot--on-doc-focus 'local)
12691303
(remove-hook 'kill-buffer-hook #'copilot--on-doc-close 'local)
1304+
(when copilot--track-changes-id
1305+
(track-changes-unregister copilot--track-changes-id)
1306+
(setq copilot--track-changes-id nil))
12701307
;; Send the close event for the active buffer since activating the mode will open it again.
12711308
(copilot--on-doc-close))
12721309

0 commit comments

Comments
 (0)