coc-git 2.4.8 → 2.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/Readme.md +1 -2
  2. package/lib/index.js +166 -17
  3. package/package.json +13 -9
package/Readme.md CHANGED
@@ -61,8 +61,6 @@ In your vim/neovim, run command:
61
61
 
62
62
  - `git.browserBranchName`: Branch name for browserOpen and copyUrl., default: `""`
63
63
 
64
- - `git.urlMode`: URL mode for browserOpen and copyUrl, you can set it to `"permalink"`. default: `"normal"`
65
-
66
64
  - `git.urlFix`: a object to configure the url style of copyUrl and browserOpen, make this two command support other git services like gitlab and gitea. default: `{}`
67
65
 
68
66
  - `git.issueFormat`: Formatting string for issue completion. Supported interpolation variables: %i - issue id. %r - repository name. %o - organization/owner name. %t - issue title. %b - issue body. %c - issue created at. %a - issue author. %u - issue url., default: `"#%i"`
@@ -222,6 +220,7 @@ related commands.
222
220
  - `:CocCommand git.chunkInfo` Show chunk info under cursor.
223
221
  - `:CocCommand git.chunkUndo` Undo current chunk.
224
222
  - `:CocCommand git.chunkStage` Stage current chunk.
223
+ - `:CocCommand git.chunkUnstage` Unstage chunk that contains current line.
225
224
  - `:CocCommand git.diffCached` Show cached diff in preview window.
226
225
  - `:CocCommand git.showCommit` Show commit of current chunk.
227
226
  - `:CocCommand git.browserOpen` Open current line in browser
package/lib/index.js CHANGED
@@ -4565,6 +4565,30 @@ var import_child_process = __toModule(require("child_process"));
4565
4565
  var import_coc = __toModule(require("coc.nvim"));
4566
4566
  var import_path = __toModule(require("path"));
4567
4567
  var import_which = __toModule(require_which());
4568
+ function reverseLine(line) {
4569
+ if (line.startsWith("-"))
4570
+ return "+" + line.slice(1);
4571
+ if (line.startsWith("+"))
4572
+ return "-" + line.slice(1);
4573
+ return line;
4574
+ }
4575
+ function createUnstagePatch(relpath, chunk) {
4576
+ if (chunk.remove.count == 0 && chunk.add.count == 0)
4577
+ return "";
4578
+ let head = `@@ -${chunk.add.lnum},${chunk.add.count} +${chunk.add.lnum + 1 - chunk.add.count},${chunk.remove.count} @@`;
4579
+ if (!head)
4580
+ return "";
4581
+ const lines = [
4582
+ `diff --git a/${relpath} b/${relpath}`,
4583
+ `index 000000..000000 100644`,
4584
+ `--- a/${relpath}`,
4585
+ `+++ b/${relpath}`,
4586
+ head
4587
+ ];
4588
+ lines.push(...chunk.lines.map((s) => reverseLine(s)));
4589
+ lines.push("");
4590
+ return lines.join("\n");
4591
+ }
4568
4592
  function wait(ms) {
4569
4593
  return new Promise((resolve) => {
4570
4594
  setTimeout(() => {
@@ -4900,20 +4924,19 @@ var Bcommits = class extends import_coc2.BasicList {
4900
4924
  }, {tabPersist: true});
4901
4925
  this.addAction("view", async (item, context) => {
4902
4926
  let {commit, root, file} = item.data;
4903
- let {window: window9, listWindow} = context;
4927
+ let {window: window9} = context;
4904
4928
  let content = await import_coc2.runCommand(`git show ${commit}:${shellescape(file)}`, {cwd: root});
4905
4929
  let lines = content.replace(/\n$/, "").split("\n");
4906
4930
  nvim.pauseNotification();
4907
4931
  nvim.call("win_gotoid", [window9.id], true);
4908
- nvim.command(`exe "edit ".fnameescape('(${commit}) ${file}')`, true);
4932
+ nvim.command(`exe "tabe ".fnameescape('(${commit}) ${file}')`, true);
4909
4933
  nvim.call("append", [0, lines], true);
4910
4934
  nvim.command("normal! Gdd", true);
4911
4935
  nvim.command(`exe 1`, true);
4912
4936
  nvim.command("setl buftype=nofile nomodifiable bufhidden=wipe nobuflisted", true);
4913
4937
  nvim.command("filetype detect", true);
4914
- nvim.call("win_gotoid", [listWindow.id], true);
4915
4938
  await nvim.resumeNotification();
4916
- }, {persist: true});
4939
+ }, {persist: false});
4917
4940
  this.addAction("diff", async (item, context) => {
4918
4941
  let buffer = await context.window.buffer;
4919
4942
  let filetype = await buffer.getOption("filetype");
@@ -5226,7 +5249,7 @@ var Commits = class extends import_coc4.BasicList {
5226
5249
  } else {
5227
5250
  arg = `${list[1].data.commit} ${list[0].data.commit}`;
5228
5251
  }
5229
- let content = await runCommand(`git --no-pager diff ${arg}`, {cwd: list[0].data.root});
5252
+ let content = await runCommand(`git --no-pager diff --no-ext-diff ${arg}`, {cwd: list[0].data.root});
5230
5253
  let lines = content.replace(/\n$/, "").split("\n");
5231
5254
  nvim.pauseNotification();
5232
5255
  nvim.command(`tabe [diff ${arg}]`, true);
@@ -5250,7 +5273,7 @@ var Commits = class extends import_coc4.BasicList {
5250
5273
  } else {
5251
5274
  arg = `${list[1].data.commit} ${list[0].data.commit}`;
5252
5275
  }
5253
- let content = await runCommand(`git --no-pager diff ${arg}`, {cwd: list[0].data.root});
5276
+ let content = await runCommand(`git --no-pager diff --no-ext-diff ${arg}`, {cwd: list[0].data.root});
5254
5277
  let lines = content.replace(/\n$/, "").split("\n");
5255
5278
  let winid = context.listWindow.id;
5256
5279
  let mod = context.options.position == "tab" ? "below" : "above";
@@ -5346,7 +5369,7 @@ var Gfiles = class extends import_coc5.BasicList {
5346
5369
  let {root, sha, filepath, branch} = item.data;
5347
5370
  if (!sha)
5348
5371
  return;
5349
- let content = await runCommand(`git --no-pager diff ${branch} -- ${shellescape(filepath)}`, {cwd: root});
5372
+ let content = await runCommand(`git --no-pager diff --no-ext-diff ${branch} -- ${shellescape(filepath)}`, {cwd: root});
5350
5373
  let lines = content.replace(/\n$/, "").split("\n");
5351
5374
  await this.preview({
5352
5375
  lines,
@@ -5478,7 +5501,7 @@ var GStatus = class extends import_coc6.BasicList {
5478
5501
  }, context);
5479
5502
  return;
5480
5503
  }
5481
- let args = ["--no-pager", "diff"];
5504
+ let args = ["--no-pager", "diff", "--no-ext-diff"];
5482
5505
  if (index_symbol == "M" && tree_symbol != "M") {
5483
5506
  args.push("--cached");
5484
5507
  }
@@ -5840,6 +5863,12 @@ var DocumentManager = class {
5840
5863
  return;
5841
5864
  await buf.chunkStage();
5842
5865
  }
5866
+ async chunkUnstage() {
5867
+ let buf = await this.buffer;
5868
+ if (!buf)
5869
+ return;
5870
+ await buf.chunkUnstage();
5871
+ }
5843
5872
  async chunkUndo() {
5844
5873
  let buf = await this.buffer;
5845
5874
  if (buf)
@@ -5850,10 +5879,16 @@ var DocumentManager = class {
5850
5879
  if (buf)
5851
5880
  await buf.showCommit();
5852
5881
  }
5853
- async browser(action = "open", range) {
5882
+ async showBlameDoc() {
5854
5883
  let buf = await this.buffer;
5884
+ let line = await this.nvim.call("line", ".");
5855
5885
  if (buf)
5856
- await buf.browser(action, range);
5886
+ await buf.showBlameDoc(line);
5887
+ }
5888
+ async browser(action = "open", range, permalink = false) {
5889
+ let buf = await this.buffer;
5890
+ if (buf)
5891
+ await buf.browser(action, range, permalink);
5857
5892
  }
5858
5893
  async diffCached() {
5859
5894
  let buf = await this.buffer;
@@ -5929,6 +5964,48 @@ var Repo = class {
5929
5964
  this.channel = channel;
5930
5965
  this.root = root;
5931
5966
  }
5967
+ async getStagedChunks(relpath) {
5968
+ let args = ["--no-pager", "diff", "--no-ext-diff", "-p", "-U0", "--no-color", "--staged"];
5969
+ if (relpath)
5970
+ args.push(toUnixSlash(relpath));
5971
+ const result = await this.exec(args);
5972
+ if (!result.stdout) {
5973
+ throw new Error(`No staged result.`);
5974
+ }
5975
+ let res = {};
5976
+ let idx = 0;
5977
+ let lines = result.stdout.split(/\r?\n/);
5978
+ let curr;
5979
+ let fsPath;
5980
+ while (idx < lines.length) {
5981
+ let line = lines[idx];
5982
+ if (fsPath && line.startsWith("@@")) {
5983
+ curr = void 0;
5984
+ let ms = line.match(/^@@\s+-(\d+),?(\d*)\s+\+(\d+),?(\d*)\s+@@/);
5985
+ if (ms) {
5986
+ curr = {
5987
+ remove: {lnum: Number(ms[1]), count: ms[2] ? Number(ms[2]) : 1},
5988
+ add: {lnum: Number(ms[3]), count: ms[4] ? Number(ms[4]) : 1},
5989
+ lines: []
5990
+ };
5991
+ res[fsPath] = res[fsPath] || [];
5992
+ res[fsPath].push(curr);
5993
+ }
5994
+ } else if (curr && /^[+\-]/.test(line)) {
5995
+ curr.lines.push(line);
5996
+ } else if (line.startsWith("diff --git")) {
5997
+ let ms = line.match(/diff\s--git\sa\/(.*)\sb\//);
5998
+ if (ms) {
5999
+ fsPath = ms[1];
6000
+ curr = void 0;
6001
+ idx += 4;
6002
+ continue;
6003
+ }
6004
+ }
6005
+ idx++;
6006
+ }
6007
+ return res;
6008
+ }
5932
6009
  async getHEAD() {
5933
6010
  try {
5934
6011
  const result = await this.exec(["symbolic-ref", "--short", "HEAD"]);
@@ -6037,7 +6114,7 @@ var Repo = class {
6037
6114
  const currentFile = import_path4.default.join(import_os.default.tmpdir(), `coc-${uuid()}`);
6038
6115
  await import_util6.default.promisify(import_fs2.default.writeFile)(stagedFile, staged + "\n", "utf8");
6039
6116
  await import_util6.default.promisify(import_fs2.default.writeFile)(currentFile, content, "utf8");
6040
- let output = await getStdout(`git --no-pager diff -p -U0 --no-color ${shellescape(stagedFile)} ${shellescape(currentFile)}`);
6117
+ let output = await getStdout(`git --no-pager diff --no-ext-diff -p -U0 --no-color ${shellescape(stagedFile)} ${shellescape(currentFile)}`);
6041
6118
  await import_util6.default.promisify(import_fs2.default.unlink)(stagedFile);
6042
6119
  await import_util6.default.promisify(import_fs2.default.unlink)(currentFile);
6043
6120
  if (!output)
@@ -6558,6 +6635,49 @@ var GitBuffer = class {
6558
6635
  this.channel.appendLine(`[Error] ${e.message}`);
6559
6636
  }
6560
6637
  }
6638
+ async chunkUnstage() {
6639
+ let {nvim} = import_coc11.workspace;
6640
+ const {diffs} = this;
6641
+ let line = await nvim.call("line", ".");
6642
+ let adjust = 0;
6643
+ let invalid = false;
6644
+ for (let diff of diffs) {
6645
+ if (diff.end >= line) {
6646
+ if (diff.start <= line && diff.changeType != ChangeType.Delete) {
6647
+ import_coc11.window.showErrorMessage(`Current line contains unstaged change.`);
6648
+ invalid = true;
6649
+ }
6650
+ break;
6651
+ }
6652
+ adjust -= diff.added.count;
6653
+ adjust += diff.removed.count;
6654
+ }
6655
+ if (invalid)
6656
+ return;
6657
+ line = line + adjust;
6658
+ let stagedDiff = await this.repo.getStagedChunks(this.relpath);
6659
+ let chunks = Object.values(stagedDiff)[0];
6660
+ if (!chunks.length) {
6661
+ import_coc11.window.showErrorMessage(`Staged chunk not found`);
6662
+ return;
6663
+ }
6664
+ let chunk = chunks.find((o) => o.add.lnum <= line && o.add.lnum + o.add.count >= line);
6665
+ if (!chunk) {
6666
+ import_coc11.window.showErrorMessage(`Unable to find staged chunk on current line`);
6667
+ return;
6668
+ }
6669
+ this.channel.appendLine(`[Info] resolved chunk ${JSON.stringify(chunk, null, 2)}`);
6670
+ let patch = createUnstagePatch(this.relpath, chunk);
6671
+ if (!patch)
6672
+ return;
6673
+ try {
6674
+ await this.git.exec(this.repo.root, ["apply", "--cached", "--unidiff-zero", "-"], {input: patch});
6675
+ this.refresh();
6676
+ } catch (e) {
6677
+ import_coc11.window.showErrorMessage(`Unable to apply patch: ${e.message}`);
6678
+ this.channel.appendLine(`[Error] ${e.message}`);
6679
+ }
6680
+ }
6561
6681
  async nextChunk() {
6562
6682
  const {diffs} = this;
6563
6683
  let {nvim} = import_coc11.workspace;
@@ -6642,6 +6762,24 @@ var GitBuffer = class {
6642
6762
  }
6643
6763
  }
6644
6764
  }
6765
+ async showBlameDoc(lnum) {
6766
+ let indexed = await this.repo.isIndexed(this.relpath);
6767
+ if (!indexed) {
6768
+ import_coc11.window.showMessage("File not indexed");
6769
+ } else {
6770
+ let infos = await this.getBlameInfo();
6771
+ let info = infos.find((o) => lnum >= o.startLnum && lnum <= o.endLnum);
6772
+ if (info && info.author && info.author != "Not Committed Yet") {
6773
+ let blameText = [];
6774
+ blameText.push(`${info.author}, ${info.time}`);
6775
+ blameText.push(`${info.summary}`);
6776
+ blameText.push(`${info.sha.substring(0, 7)}`);
6777
+ await this.showDoc(blameText.join("\n\n"), "text");
6778
+ } else {
6779
+ import_coc11.window.showMessage("Not committed yet");
6780
+ }
6781
+ }
6782
+ }
6645
6783
  async diffDocument(force = false) {
6646
6784
  var _a;
6647
6785
  let {nvim} = import_coc11.workspace;
@@ -6869,10 +7007,9 @@ var GitBuffer = class {
6869
7007
  }
6870
7008
  import_coc11.window.showMessage("Not positioned on a conflict");
6871
7009
  }
6872
- async browser(action = "open", range) {
7010
+ async browser(action = "open", range, permalink = false) {
6873
7011
  let {nvim} = import_coc11.workspace;
6874
7012
  let config = import_coc11.workspace.getConfiguration("git");
6875
- let mode = config.get("urlMode", "normal").trim();
6876
7013
  let head = (await this.repo.safeRun(["rev-parse", "HEAD"])).trim();
6877
7014
  let branch = config.get("browserBranchName", "").trim();
6878
7015
  if (!branch.length) {
@@ -6914,16 +7051,16 @@ var GitBuffer = class {
6914
7051
  let hostname = tmp.hostname;
6915
7052
  let fix = "|";
6916
7053
  try {
6917
- fix = config.get("urlFix")[hostname][mode == "permalink" ? 1 : 0];
7054
+ fix = config.get("urlFix")[hostname][permalink ? 1 : 0];
6918
7055
  } catch (e) {
6919
7056
  }
6920
- let url = getUrl(fix, repoURL, mode == "permalink" ? head : branch, this.relpath.replace(/\\\\/g, "/"), lines);
7057
+ let url = getUrl(fix, repoURL, permalink ? head : branch, this.relpath.replace(/\\\\/g, "/"), lines);
6921
7058
  if (url)
6922
7059
  urls.push(url);
6923
7060
  }
6924
7061
  if (urls.length == 1) {
6925
7062
  if (action == "open") {
6926
- nvim.call("coc#util#open_url", [urls[0]], true);
7063
+ await import_coc11.workspace.openResource(urls[0]);
6927
7064
  } else {
6928
7065
  nvim.command(`let @+ = '${urls[0]}'`, true);
6929
7066
  import_coc11.window.showMessage("Copied url to clipboard");
@@ -6932,7 +7069,7 @@ var GitBuffer = class {
6932
7069
  let idx = await import_coc11.window.showQuickpick(urls, "Select url:");
6933
7070
  if (idx >= 0) {
6934
7071
  if (action == "open") {
6935
- nvim.call("coc#util#open_url", [urls[idx]], true);
7072
+ await import_coc11.workspace.openResource(urls[idx]);
6936
7073
  } else {
6937
7074
  nvim.command(`let @+ = '${urls[idx]}'`, true);
6938
7075
  import_coc11.window.showMessage("Copied url to clipboard");
@@ -7619,6 +7756,9 @@ async function activate(context) {
7619
7756
  subscriptions.push(import_coc14.workspace.registerKeymap(["n"], "git-commit", async () => {
7620
7757
  await manager.showCommit();
7621
7758
  }, {sync: false}));
7759
+ subscriptions.push(import_coc14.workspace.registerKeymap(["n"], "git-showblamedoc", async () => {
7760
+ await manager.showBlameDoc();
7761
+ }, {sync: false}));
7622
7762
  subscriptions.push(import_coc14.commands.registerCommand("git.keepCurrent", async () => {
7623
7763
  await manager.keepCurrent();
7624
7764
  }));
@@ -7634,6 +7774,9 @@ async function activate(context) {
7634
7774
  subscriptions.push(import_coc14.commands.registerCommand("git.chunkStage", async () => {
7635
7775
  await manager.chunkStage();
7636
7776
  }));
7777
+ subscriptions.push(import_coc14.commands.registerCommand("git.chunkUnstage", async () => {
7778
+ await manager.chunkUnstage();
7779
+ }));
7637
7780
  subscriptions.push(import_coc14.commands.registerCommand("git.chunkUndo", async () => {
7638
7781
  await manager.chunkUndo();
7639
7782
  }));
@@ -7646,6 +7789,9 @@ async function activate(context) {
7646
7789
  subscriptions.push(import_coc14.commands.registerCommand("git.copyUrl", async (...args) => {
7647
7790
  await manager.browser("copy", args);
7648
7791
  }));
7792
+ subscriptions.push(import_coc14.commands.registerCommand("git.copyPermalink", async (...args) => {
7793
+ await manager.browser("copy", args, true);
7794
+ }));
7649
7795
  subscriptions.push(import_coc14.commands.registerCommand("git.push", async (...args) => {
7650
7796
  await manager.push(args);
7651
7797
  }));
@@ -7658,6 +7804,9 @@ async function activate(context) {
7658
7804
  subscriptions.push(import_coc14.commands.registerCommand("git.foldUnchanged", async () => {
7659
7805
  await manager.toggleFold();
7660
7806
  }));
7807
+ subscriptions.push(import_coc14.commands.registerCommand("git.showBlameDoc", async () => {
7808
+ await manager.showBlameDoc();
7809
+ }));
7661
7810
  subscriptions.push(import_coc14.listManager.registerList(new gstatus_default(nvim, manager)));
7662
7811
  subscriptions.push(import_coc14.listManager.registerList(new branches_default(nvim, manager)));
7663
7812
  subscriptions.push(import_coc14.listManager.registerList(new commits_default(nvim, manager)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coc-git",
3
- "version": "2.4.8",
3
+ "version": "2.4.11",
4
4
  "description": "Git extension for coc.nvim",
5
5
  "main": "lib/index.js",
6
6
  "publisher": "chemzqm",
@@ -35,6 +35,10 @@
35
35
  "title": "Stage current chunk.",
36
36
  "command": "git.chunkStage"
37
37
  },
38
+ {
39
+ "title": "Unstage chunk that contains current line",
40
+ "command": "git.chunkUnstage"
41
+ },
38
42
  {
39
43
  "title": "Undo current chunk.",
40
44
  "command": "git.chunkUndo"
@@ -51,6 +55,10 @@
51
55
  "title": "Copy url of current line to clipboard, github url supported.",
52
56
  "command": "git.copyUrl"
53
57
  },
58
+ {
59
+ "title": "Copy permalink of current line to clipboard, github url supported.",
60
+ "command": "git.copyPermalink"
61
+ },
54
62
  {
55
63
  "title": "Show cached diff in preview window.",
56
64
  "command": "git.diffCached"
@@ -66,6 +74,10 @@
66
74
  {
67
75
  "title": "Push code of current branch to remote",
68
76
  "command": "git.push"
77
+ },
78
+ {
79
+ "title": "Show git blame info in float or popup window",
80
+ "command": "git.showBlameDoc"
69
81
  }
70
82
  ],
71
83
  "configuration": {
@@ -91,14 +103,6 @@
91
103
  "default": "",
92
104
  "description": "Branch name for browserOpen and copyUrl."
93
105
  },
94
- "git.urlMode": {
95
- "type": "string",
96
- "default": "normal",
97
- "enum": [
98
- "normal",
99
- "permalink"
100
- ]
101
- },
102
106
  "git.urlFix": {
103
107
  "type": "object",
104
108
  "default": {},