|
38 | 38 | ;; See https://phpactor.github.io/phpactor/configuration.html |
39 | 39 | ;; |
40 | 40 |
|
| 41 | +;; The following definitions from go-mode.el have been adapted : |
| 42 | +;; (Author: Dominik Honnef, url: https://github.com/dominikh/go-mode.el) |
| 43 | +;; |
| 44 | +;; go--apply-rcs-patch go--goto-line go--delete-whole-line |
| 45 | + |
41 | 46 | ;;; Code: |
42 | 47 | (require 'json) |
43 | 48 | (require 'php-project) |
|
265 | 270 | (find-file path) |
266 | 271 | (goto-char (1+ offset))) |
267 | 272 |
|
268 | | -(cl-defun phpactor-action-replace-file-source (&key path source) |
| 273 | +;; this function was adapted from go-mode |
| 274 | +(defun phpactor--goto-line (line) |
| 275 | + "Goto line LINE." |
| 276 | + (goto-char (point-min)) |
| 277 | + (forward-line (1- line))) |
| 278 | + |
| 279 | +;; this function was adapted from go-mode |
| 280 | +(defun phpactor--delete-whole-line (&optional arg) |
| 281 | + "Delete the current line without putting it in the `kill-ring'. |
| 282 | +Derived from function `kill-whole-line'. ARG is defined as for that |
| 283 | +function." |
| 284 | + (setq arg (or arg 1)) |
| 285 | + (if (and (> arg 0) |
| 286 | + (eobp) |
| 287 | + (save-excursion (forward-visible-line 0) (eobp))) |
| 288 | + (signal 'end-of-buffer nil)) |
| 289 | + (if (and (< arg 0) |
| 290 | + (bobp) |
| 291 | + (save-excursion (end-of-visible-line) (bobp))) |
| 292 | + (signal 'beginning-of-buffer nil)) |
| 293 | + (cond ((zerop arg) |
| 294 | + (delete-region (progn (forward-visible-line 0) (point)) |
| 295 | + (progn (end-of-visible-line) (point)))) |
| 296 | + ((< arg 0) |
| 297 | + (delete-region (progn (end-of-visible-line) (point)) |
| 298 | + (progn (forward-visible-line (1+ arg)) |
| 299 | + (unless (bobp) |
| 300 | + (backward-char)) |
| 301 | + (point)))) |
| 302 | + (t |
| 303 | + (delete-region (progn (forward-visible-line 0) (point)) |
| 304 | + (progn (forward-visible-line arg) (point)))))) |
| 305 | + |
| 306 | +;; this function was adapted from go-mode |
| 307 | +(defun phpactor--apply-rcs-patch (patch-buffer) |
| 308 | + "Apply an RCS-formatted diff from PATCH-BUFFER to the current buffer." |
| 309 | + (let ((target-buffer (current-buffer)) |
| 310 | + ;; Relative offset between buffer line numbers and line numbers |
| 311 | + ;; in patch. |
| 312 | + ;; |
| 313 | + ;; Line numbers in the patch are based on the source file, so |
| 314 | + ;; we have to keep an offset when making changes to the |
| 315 | + ;; buffer. |
| 316 | + ;; |
| 317 | + ;; Appending lines decrements the offset (possibly making it |
| 318 | + ;; negative), deleting lines increments it. This order |
| 319 | + ;; simplifies the forward-line invocations. |
| 320 | + (line-offset 0) |
| 321 | + (column (current-column))) |
| 322 | + (save-excursion |
| 323 | + (with-current-buffer patch-buffer |
| 324 | + (goto-char (point-min)) |
| 325 | + (while (not (eobp)) |
| 326 | + (unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)") |
| 327 | + (error "Invalid rcs patch or internal error in go--apply-rcs-patch")) |
| 328 | + (forward-line) |
| 329 | + (let ((action (match-string 1)) |
| 330 | + (from (string-to-number (match-string 2))) |
| 331 | + (len (string-to-number (match-string 3)))) |
| 332 | + (cond |
| 333 | + ((equal action "a") |
| 334 | + (let ((start (point))) |
| 335 | + (forward-line len) |
| 336 | + (let ((text (buffer-substring start (point)))) |
| 337 | + (with-current-buffer target-buffer |
| 338 | + (cl-decf line-offset len) |
| 339 | + (goto-char (point-min)) |
| 340 | + (forward-line (- from len line-offset)) |
| 341 | + (insert text))))) |
| 342 | + ((equal action "d") |
| 343 | + (with-current-buffer target-buffer |
| 344 | + (phpactor--goto-line (- from line-offset)) |
| 345 | + (cl-incf line-offset len) |
| 346 | + (phpactor--delete-whole-line len))) |
| 347 | + (t |
| 348 | + (error "Invalid rcs patch or internal error in phpactor--apply-rcs-patch"))))))) |
| 349 | + (move-to-column column))) |
| 350 | + |
| 351 | +(cl-defun phpactor-action-replace-file-source (&key path source) |
269 | 352 | "Replace the source code in the current file." |
270 | | - (save-window-excursion |
271 | | - (with-current-buffer (find-file-noselect path) |
272 | | - ;; This is a simple implementation, so points will not be saved. |
273 | | - ;; Should I copy the implementation of gofmt? Umm... |
274 | | - (erase-buffer) |
275 | | - (insert source)))) |
| 353 | + (interactive) |
| 354 | + (let ((tmpfile (make-temp-file "phpactor" nil ".php")) |
| 355 | + (patchbuf (get-buffer-create "*Phpactor patch*")) |
| 356 | + (coding-system-for-read 'utf-8) |
| 357 | + (coding-system-for-write 'utf-8)) |
| 358 | + |
| 359 | + (unwind-protect |
| 360 | + (save-restriction |
| 361 | + (widen) |
| 362 | + (with-current-buffer patchbuf |
| 363 | + (erase-buffer)) |
| 364 | + |
| 365 | + (with-temp-file tmpfile |
| 366 | + (insert source)) |
| 367 | + |
| 368 | + (if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile)) |
| 369 | + (message "Buffer was unchanged by phpactor") |
| 370 | + (phpactor--apply-rcs-patch patchbuf) |
| 371 | + (message "Buffer modified by phpactor"))) |
| 372 | + |
| 373 | + (kill-buffer patchbuf) |
| 374 | + (delete-file tmpfile)))) |
276 | 375 |
|
277 | 376 | ;; Dispatcher: |
278 | 377 | (cl-defun phpactor-action-dispatch (&key action parameters) |
|
369 | 468 | (let ((arguments (phpactor--command-argments :source :offset :path))) |
370 | 469 | (apply #'phpactor-action-dispatch (phpactor--rpc "goto_definition" arguments)))) |
371 | 470 |
|
| 471 | +;;;###autoload |
| 472 | +(defun phpactor-import-class (name) |
| 473 | + "Execute Phpactor PRC import_class command for class NAME." |
| 474 | + (interactive) |
| 475 | + (let ((arguments (phpactor--command-argments :source :offset :path))) |
| 476 | + (apply #'phpactor-action-dispatch (phpactor--rpc "import_class" (append arguments (list :name name)))))) |
| 477 | + |
372 | 478 | (provide 'phpactor) |
373 | 479 | ;;; phpactor.el ends here |
0 commit comments