commit 6b6c8a7882362c36787a7522e0b0cecc463f6e3d from: Omar Polo date: Mon Jan 04 14:07:56 2021 UTC fundamentals for staging changes This is an initial implementation for the stage/unstage functionalities. They operate at a smaller scope than filesets, the work with individual hunks. An interactive stage hunks and a unstage-all are implemented. commit - 43c93a89a7024d8b8556207cd1404c6b563249e8 commit + 6b6c8a7882362c36787a7522e0b0cecc463f6e3d blob - 68acf98232b6d7e8aaef75c327e3280e38f8d46b blob + b1e208b6d15542a4a4be80b779f8281785a743c2 --- Makefile +++ Makefile @@ -1,6 +1,6 @@ EMACS = emacs -compile: vc-got.elc +compile: vc-got.elc vc-got-stage.elc clean: rm -f *.elc blob - 3a035360e11b5efb8001874a0012799e0abf45b2 blob + 32a11f72a6c4ea4dee043dc99a9a350e5785d8cb --- vc-got.el +++ vc-got.el @@ -133,6 +133,8 @@ (require 'seq) (require 'vc) (require 'vc-annotate) + +(require 'vc-got-stage) (defgroup vc-got nil "VC GoT backend." @@ -324,6 +326,12 @@ DIR-OR-FILE." (apply #'vc-got--call "diff" (append (vc-switches 'got 'diff) (mapcar #'file-relative-name args)))) + +(defun vc-got--unstage (file-or-directory) + "Unstage all the staged hunks at or within FILE-OR-DIRECTORY. +If it's nil, unstage every staged changes across the entire work +tree." + (vc-got--call "unstage" file-or-directory)) (defun vc-got--remove (file &optional force keep-local) "Internal helper to removing FILE from got." blob - /dev/null blob + baf0e43679ec4f8185715c304432836c0872e230 (mode 644) --- /dev/null +++ vc-got-stage.el @@ -0,0 +1,129 @@ +;;; vc-got-stage.el --- Stage functionalities for vc-got -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Omar Polo + +;; Author: Omar Polo +;; Keywords: vc + +;; 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: + +;; Stage-related functions for vc-got. This allows vc-got to stage +;; and commit individual chunks and not entire filesets. + +;;; Code: + +(require 'vc) + +(defvar vc-got-program) ;vc-got.el +(declare-function vc-got--diff "vc-got") +(declare-function vc-got--unstage "vc-got" (file)) + +(defvar vc-got-stage--process nil + "The got stage process.") + +(defvar vc-got-stage--fileset nil + "Remaining fileset to process.") + +(defun vc-got-stage--assert-proc () + "Assert no vc-got-stage process is running." + (when (process-live-p vc-got-stage--process) + (error "A vc-got-stage-files is already in progress"))) + +(defun vc-got-stage-files (fileset) + "Interactively stage hunks from files in FILESET." + (interactive (list (cadr (vc-deduce-fileset)))) + (vc-got-stage--assert-proc) + (if (not fileset) + (message "[vc-got] nothing to stage.") + (setq vc-got-stage--fileset fileset) + (vc-got-stage--next))) + +(defun vc-got-stage--next () + "Process next file in stage list." + (vc-got-stage--assert-proc) + (let ((file (car vc-got-stage--fileset))) + (if (not file) + (progn (kill-buffer (process-buffer vc-got-stage--process)) + (message "[vc-got] stage done.")) + (setq vc-got-stage--fileset (cdr vc-got-stage--fileset)) + (let ((buf (get-buffer-create "*vc-got-stage*"))) + (pop-to-buffer buf) + (with-current-buffer buf + (buffer-disable-undo) + (erase-buffer) + (read-only-mode) + (unless (derived-mode-p 'diff-mode) + (diff-mode))) + (setq vc-got-stage--process + (make-process :name "got" + :buffer buf + :command (list vc-got-program "stage" "-p" file) + :connection 'pty + :filter #'vc-got-stage--filter + :sentinel #'vc-got-stage--sentinel)))))) + +(defun vc-got-stage--filter (proc string) + "Filter for got stage process. +PROC is the process, STRING part of its output." + (let ((buf (process-buffer proc))) + (when (buffer-live-p buf) + (let ((inhibit-read-only t)) + (with-current-buffer buf + (goto-char (point-max)) + (insert string) + (save-excursion + (beginning-of-line) + (let ((msg (cond ((looking-at "^stage this change?") + "Stage this change? ") + ((looking-at "^stage this addition?") + "Stage this addition? ")))) + (when msg + (kill-line) + (process-send-string buf (if (y-or-n-p msg) "y\n" "n\n")) + (erase-buffer))))))))) + +(defun vc-got-stage--sentinel (_proc event) + "Sentinel for got stage process. +Should be only called when EVENT is finished." + (when (string= event "finished\n") + (vc-got-stage--next))) + +;; TODO: make this interactive just as stage is +(defun vc-got-stage-unstage (fileset) + "Unstage staged hunks in FILESET." + (interactive (list (cadr (vc-deduce-fileset)))) + (vc-got-stage--assert-proc) + (if fileset + (dolist (file fileset) + (vc-got--unstage file)) + (vc-got--unstage nil))) + +(defun vc-got-stage-diff (fileset) + "Pop a buffer with the staged diff for FILESET. +If FILESET is nil, show the diff for every staged hunks." + (interactive (list (cadr (vc-deduce-fileset)))) + (with-current-buffer (get-buffer-create "*vc-diff*") + (pop-to-buffer (current-buffer)) + (let ((inhibit-read-only t)) + (erase-buffer) + (diff-mode) + (if fileset + (dolist (file fileset) + (vc-got--diff "-s" file)) + (vc-got--diff "-s"))))) + +(provide 'vc-got-stage) +;;; vc-got-stage.el ends here