coc-git 2.7.8 → 2.7.9

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.
package/lib/index.js CHANGED
@@ -5854,6 +5854,18 @@ var DocumentManager = class {
5854
5854
  nvim.command(`sign define CocGit${item} text=${text} texthl=CocGit${item}Sign`, true);
5855
5855
  nvim.command(`highlight default link CocGit${item}Sign ${hlGroup}`, true);
5856
5856
  }
5857
+ const stagedItems = [
5858
+ ["StagedAdded", "stagedAddedSign", "CocGitStagedAdd", "DiffAdd"],
5859
+ ["StagedChanged", "stagedChangedSign", "CocGitStagedChange", "DiffChange"],
5860
+ ["StagedRemoved", "stagedRemovedSign", "CocGitStagedDelete", "DiffDelete"],
5861
+ ["Mixed", "mixedSign", "CocGitMixed", "WarningMsg"]
5862
+ ];
5863
+ for (let [item, section, defaultGroup, fallback] of stagedItems) {
5864
+ let text = config.get(`${section}.text`, "");
5865
+ let hlGroup = config.get(`${section}.hlGroup`, defaultGroup);
5866
+ nvim.command(`sign define CocGit${item} text=${text} texthl=${hlGroup}`, true);
5867
+ nvim.command(`highlight default link ${hlGroup} ${fallback}`, true);
5868
+ }
5857
5869
  await nvim.resumeNotification();
5858
5870
  }
5859
5871
  loadConfiguration(e) {
@@ -5873,8 +5885,10 @@ var DocumentManager = class {
5873
5885
  blameUseRealTime: config.get("blameUseRealTime", false),
5874
5886
  enableGutters: config.get("enableGutters", true),
5875
5887
  realtimeGutters: config.get("realtimeGutters", true),
5888
+ enableStagedGutters: config.get("enableStagedGutters", false),
5876
5889
  showCommitInFloating: config.get("showCommitInFloating", false),
5877
5890
  signPriority: config.get("signPriority", 10),
5891
+ stagedSignPriority: config.get("stagedSignPriority", 9),
5878
5892
  pushArguments: (_a = config.get("pushArguments")) != null ? _a : [],
5879
5893
  splitWindowCommand: config.get("splitWindowCommand", "above sp"),
5880
5894
  changedSign: {
@@ -5897,6 +5911,22 @@ var DocumentManager = class {
5897
5911
  text: config.get("changeRemovedSign.text", "\u2243"),
5898
5912
  hlGroup: config.get("changeRemovedSign.hlGroup", "DiffChange")
5899
5913
  },
5914
+ stagedAddedSign: {
5915
+ text: config.get("stagedAddedSign.text", "\u2503"),
5916
+ hlGroup: config.get("stagedAddedSign.hlGroup", "CocGitStagedAdd")
5917
+ },
5918
+ stagedChangedSign: {
5919
+ text: config.get("stagedChangedSign.text", "\u2503"),
5920
+ hlGroup: config.get("stagedChangedSign.hlGroup", "CocGitStagedChange")
5921
+ },
5922
+ stagedRemovedSign: {
5923
+ text: config.get("stagedRemovedSign.text", "\u257B"),
5924
+ hlGroup: config.get("stagedRemovedSign.hlGroup", "CocGitStagedDelete")
5925
+ },
5926
+ mixedSign: {
5927
+ text: config.get("mixedSign.text", "\u250B"),
5928
+ hlGroup: config.get("mixedSign.hlGroup", "CocGitMixed")
5929
+ },
5900
5930
  conflict: {
5901
5931
  enabled: config.get("conflict.enabled", true),
5902
5932
  currentHlGroup: config.get("conflict.current.hlGroup", "DiffChange"),
@@ -5913,7 +5943,11 @@ var DocumentManager = class {
5913
5943
  this.config = Object.assign(this.config || {}, obj);
5914
5944
  if (e) {
5915
5945
  this.defined = false;
5916
- for (let buffer of this.buffers.values()) buffer.markConflictCheck();
5946
+ for (let buffer of this.buffers.values()) {
5947
+ buffer.markConflictCheck();
5948
+ buffer.invalidateStagedCache();
5949
+ buffer.diffDocument(true).catch((err) => this.service.log(`[Error] configuration refresh: ${err.message}`));
5950
+ }
5917
5951
  this.defineSigns().catch((err) => this.service.log(`[Error] define signs: ${err.message}`));
5918
5952
  }
5919
5953
  }
@@ -6037,6 +6071,7 @@ var DocumentManager = class {
6037
6071
  }
6038
6072
  refresh() {
6039
6073
  for (let buf of this.buffers.values()) {
6074
+ buf.invalidateStagedCache();
6040
6075
  buf.refresh();
6041
6076
  }
6042
6077
  }
@@ -6182,1469 +6217,1772 @@ register("zh_CN", zh_CN_default);
6182
6217
 
6183
6218
  // src/model/buffer.ts
6184
6219
  var import_url = require("url");
6185
- var signGroup = "CocGit";
6186
- var revPattern = "([0-9A-Za-z_.:/-]+)";
6187
- var startPattern = new RegExp(`^<{7} (${revPattern})(:? .+)?$`);
6188
- var sepPattern = new RegExp(`^={7}$`);
6189
- var endPattern = new RegExp(`^>{7} (${revPattern})(:? .+)?$`);
6190
- var commonPattern = /^\|{7}\smerged\scommon\sancestors/;
6191
- function getPreviousConflict(conflicts, line) {
6192
- return conflicts.slice().reverse().find((conflict) => conflict.start < line);
6220
+
6221
+ // src/model/repo.ts
6222
+ var import_fs2 = __toESM(require("fs"));
6223
+ var import_os = __toESM(require("os"));
6224
+ var import_path5 = __toESM(require("path"));
6225
+ var import_util2 = __toESM(require("util"));
6226
+
6227
+ // node_modules/uuid/dist/esm/stringify.js
6228
+ var byteToHex = [];
6229
+ for (let i = 0; i < 256; ++i) {
6230
+ byteToHex.push((i + 256).toString(16).slice(1));
6193
6231
  }
6194
- function chunkContainsLine(chunk, line) {
6195
- const end = chunk.add.count === 0 ? chunk.add.lnum : chunk.add.lnum + chunk.add.count - 1;
6196
- return chunk.add.lnum <= line && end >= line;
6232
+ function unsafeStringify(arr, offset = 0) {
6233
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
6197
6234
  }
6198
- var GitBuffer = class {
6199
- constructor(doc, config, relpath, repo, git, channel, floatFactory, hasConflicts) {
6200
- this.doc = doc;
6201
- this.config = config;
6202
- this.relpath = relpath;
6203
- this.repo = repo;
6235
+
6236
+ // node_modules/uuid/dist/esm/rng.js
6237
+ var import_crypto = require("crypto");
6238
+ var rnds8Pool = new Uint8Array(256);
6239
+ var poolPtr = rnds8Pool.length;
6240
+ function rng() {
6241
+ if (poolPtr > rnds8Pool.length - 16) {
6242
+ (0, import_crypto.randomFillSync)(rnds8Pool);
6243
+ poolPtr = 0;
6244
+ }
6245
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
6246
+ }
6247
+
6248
+ // node_modules/uuid/dist/esm/native.js
6249
+ var import_crypto2 = require("crypto");
6250
+ var native_default = { randomUUID: import_crypto2.randomUUID };
6251
+
6252
+ // node_modules/uuid/dist/esm/v4.js
6253
+ function v4(options, buf, offset) {
6254
+ var _a, _b, _c;
6255
+ if (native_default.randomUUID && !buf && !options) {
6256
+ return native_default.randomUUID();
6257
+ }
6258
+ options = options || {};
6259
+ const rnds = (_c = (_b = options.random) != null ? _b : (_a = options.rng) == null ? void 0 : _a.call(options)) != null ? _c : rng();
6260
+ if (rnds.length < 16) {
6261
+ throw new Error("Random bytes length must be >= 16");
6262
+ }
6263
+ rnds[6] = rnds[6] & 15 | 64;
6264
+ rnds[8] = rnds[8] & 63 | 128;
6265
+ if (buf) {
6266
+ offset = offset || 0;
6267
+ if (offset < 0 || offset + 16 > buf.length) {
6268
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
6269
+ }
6270
+ for (let i = 0; i < 16; ++i) {
6271
+ buf[offset + i] = rnds[i];
6272
+ }
6273
+ return buf;
6274
+ }
6275
+ return unsafeStringify(rnds);
6276
+ }
6277
+ var v4_default = v4;
6278
+
6279
+ // src/model/repo.ts
6280
+ var Repo = class {
6281
+ constructor(git, channel, root) {
6204
6282
  this.git = git;
6205
6283
  this.channel = channel;
6206
- this.floatFactory = floatFactory;
6207
- this.hasConflicts = hasConflicts;
6208
- this.blameInfo = [];
6209
- this.diffs = [];
6210
- this.conflicts = [];
6211
- this.currentSigns = [];
6212
- this.gitStatus = "";
6213
- this.foldEnabled = false;
6214
- this._disposed = false;
6215
- this.mutex = new import_coc11.Mutex();
6216
- this.conflictCheckNeeded = hasConflicts;
6217
- this.refresh = (0, import_debounce2.default)(() => {
6218
- this._refresh().catch((e) => {
6219
- channel.append(`[Error] ${e.message}`);
6220
- });
6221
- }, 200);
6222
- this._refresh().catch((e) => channel.append(`[Error] ${e.message}`));
6223
- }
6224
- get cachedDiffs() {
6225
- return this.diffs;
6284
+ this.root = root;
6226
6285
  }
6227
- markConflictCheck() {
6228
- this.conflictCheckNeeded = true;
6286
+ /**
6287
+ * Get staged info
6288
+ */
6289
+ async getStagedChunks(relpath) {
6290
+ let args = ["-c", "core.quotepath=false", "--no-pager", "diff", "--no-ext-diff", "--no-renames", "-p", "-U0", "--no-color", "--staged"];
6291
+ if (relpath) args.push("--", toUnixSlash(relpath));
6292
+ const result = await this.exec(args);
6293
+ if (!result.stdout) {
6294
+ return {};
6295
+ }
6296
+ let res = {};
6297
+ let idx = 0;
6298
+ let lines = result.stdout.split(/\r?\n/);
6299
+ let curr;
6300
+ let fsPath;
6301
+ while (idx < lines.length) {
6302
+ let line = lines[idx];
6303
+ if (fsPath && line.startsWith("@@")) {
6304
+ curr = void 0;
6305
+ let ms = line.match(/^@@\s+-(\d+),?(\d*)\s+\+(\d+),?(\d*)\s+@@/);
6306
+ if (ms) {
6307
+ curr = {
6308
+ remove: { lnum: Number(ms[1]), count: ms[2] ? Number(ms[2]) : 1 },
6309
+ add: { lnum: Number(ms[3]), count: ms[4] ? Number(ms[4]) : 1 },
6310
+ lines: []
6311
+ };
6312
+ res[fsPath] = res[fsPath] || [];
6313
+ res[fsPath].push(curr);
6314
+ }
6315
+ } else if (curr && /^[+\-]/.test(line)) {
6316
+ curr.lines.push(line);
6317
+ } else if (line.startsWith("diff --git")) {
6318
+ const parsedPath = parseDiffPath(line);
6319
+ if (relpath || parsedPath) {
6320
+ fsPath = relpath ? toUnixSlash(relpath) : parsedPath;
6321
+ curr = void 0;
6322
+ idx += 4;
6323
+ continue;
6324
+ }
6325
+ }
6326
+ idx++;
6327
+ }
6328
+ return res;
6229
6329
  }
6230
- async _refresh() {
6231
- if (this._disposed) return;
6232
- this.refresh.clear();
6233
- let release = await this.mutex.acquire();
6330
+ async getHEAD() {
6234
6331
  try {
6235
- if (this._disposed) return;
6236
- let result = await Promise.all([
6237
- this.diffDocument(),
6238
- this.loadBlames(),
6239
- this.parseConflicts()
6240
- ].map((promise) => promise.then(() => void 0, (error) => error)));
6241
- result.forEach((error) => {
6242
- if (error) this.channel.append(`[Error] refresh error ${error}`);
6243
- });
6244
- } finally {
6245
- release();
6332
+ const result = await this.exec(["symbolic-ref", "--short", "HEAD"]);
6333
+ if (!result.stdout) {
6334
+ throw new Error("Not in a branch");
6335
+ }
6336
+ return result.stdout.trim();
6337
+ } catch (err) {
6338
+ const result = await this.exec(["rev-parse", "HEAD"]);
6339
+ if (!result.stdout) {
6340
+ throw new Error("Error parsing HEAD");
6341
+ }
6342
+ return result.stdout.trim();
6246
6343
  }
6247
6344
  }
6248
- getChunk(line) {
6249
- if (!this.diffs || this.diffs.length == 0) return void 0;
6250
- return this.diffs.find((ch) => {
6251
- let { start, added, removed, changeType } = ch;
6252
- if (line == 1 && start == 0 && ch.end == 0) {
6253
- return true;
6254
- }
6255
- let end = changeType === "changed" /* Change */ && added.count > removed.count ? ch.end + added.count - removed.count : ch.end;
6256
- if (start <= line && end >= line) {
6257
- return true;
6345
+ async hasChanged() {
6346
+ let result = await this.exec(["diff", "--name-status"]);
6347
+ return result.stdout.trim().length > 0;
6348
+ }
6349
+ async getStaged() {
6350
+ let result = await this.exec(["diff", "--staged", "--name-status"]);
6351
+ if (!result.stdout) return [0, 0];
6352
+ let lines = result.stdout.trim().split(/\r?\n/);
6353
+ let conflicted = 0;
6354
+ let staged = 0;
6355
+ lines.forEach((line) => {
6356
+ if (!line.length) return;
6357
+ if (line.startsWith("U")) {
6358
+ conflicted++;
6359
+ } else {
6360
+ staged++;
6258
6361
  }
6259
- return false;
6260
6362
  });
6363
+ return [conflicted, staged];
6261
6364
  }
6262
- async chunkUndo() {
6263
- let line = await import_coc11.workspace.nvim.call("line", ".");
6264
- let diff = this.getChunk(line);
6265
- if (!diff) return;
6266
- let { start, lines, changeType } = diff;
6267
- let added = lines.filter((s) => s.startsWith("-")).map((s) => s.slice(1));
6268
- let removeCount = lines.filter((s) => s.startsWith("+")).length;
6269
- let buf = this.doc.buffer;
6270
- if (changeType == "delete" /* Delete */) {
6271
- await buf.setLines(added, { start, end: start, strictIndexing: false });
6272
- } else {
6273
- await buf.setLines(added, {
6274
- start: start - 1,
6275
- end: start - 1 + removeCount,
6276
- strictIndexing: false
6365
+ async hasUntracked() {
6366
+ let cp2 = this.git.stream(this.root, ["ls-files", "--others", "--exclude-standard", "--directory"]);
6367
+ return new Promise((resolve) => {
6368
+ let settled = false;
6369
+ const finish = (value) => {
6370
+ if (settled) return;
6371
+ settled = true;
6372
+ resolve(value);
6373
+ };
6374
+ cp2.stdout.on("data", () => {
6375
+ cp2.kill("SIGKILL");
6376
+ finish(true);
6277
6377
  });
6378
+ cp2.on("exit", () => {
6379
+ finish(false);
6380
+ });
6381
+ cp2.on("error", () => {
6382
+ finish(false);
6383
+ });
6384
+ });
6385
+ }
6386
+ async getStatus(character, decorator) {
6387
+ try {
6388
+ let head = await this.getHEAD();
6389
+ if (!head) return "";
6390
+ let [changed, staged, untracked] = await Promise.all([this.hasChanged(), this.getStaged(), this.hasUntracked()]);
6391
+ const { changedDecorator, conflictedDecorator, stagedDecorator, untrackedDecorator } = decorator;
6392
+ let more = "";
6393
+ if (changed) more += changedDecorator;
6394
+ if (staged[0]) more += conflictedDecorator;
6395
+ if (staged[1]) more += stagedDecorator;
6396
+ if (untracked) more += untrackedDecorator;
6397
+ return `${character ? character + " " : ""}${head}${more}`;
6398
+ } catch (e) {
6399
+ this.channel.appendLine("Error on git status");
6400
+ this.channel.append(e.message);
6401
+ return "";
6278
6402
  }
6279
6403
  }
6280
- async chunkStage() {
6281
- let relpath = toUnixSlash(this.relpath);
6282
- let line = await import_coc11.workspace.nvim.call("line", ".");
6283
- let diff = this.getChunk(line);
6284
- if (!diff) {
6285
- import_coc11.window.showErrorMessage("Not positioned in git chunk");
6286
- return;
6287
- }
6288
- let head;
6289
- if (diff.changeType === "add" /* Add */) {
6290
- head = `@@ -${diff.removed.start + 1},0 +${diff.removed.start + 1},${diff.added.count} @@`;
6291
- } else if (diff.changeType === "delete" /* Delete */) {
6292
- head = `@@ -${diff.removed.start},${diff.removed.count} +${diff.removed.start},0 @@`;
6293
- } else if (diff.changeType === "changed" /* Change */) {
6294
- head = `@@ -${diff.removed.start},${diff.removed.count} +${diff.removed.start},${diff.added.count} @@`;
6295
- }
6296
- const from = quoteGitPath(`a/${relpath}`);
6297
- const to = quoteGitPath(`b/${relpath}`);
6298
- const lines = [
6299
- `diff --git ${from} ${to}`,
6300
- `index 000000..000000 100644`,
6301
- `--- ${from}`,
6302
- `+++ ${to}`,
6303
- head
6304
- ];
6305
- lines.push(...diff.lines);
6306
- lines.push("");
6404
+ async getDiff(relFilepath, content, revision = "", encoding = "utf8") {
6405
+ if (relFilepath.startsWith(`.git${import_path5.default.sep}`)) return;
6406
+ const base = await this.getFileContent(relFilepath, revision || ":", encoding);
6407
+ return this.getDiffFromContents(base ? base + "\n" : "", content);
6408
+ }
6409
+ async getDiffFromContents(base, content) {
6410
+ const stagedFile = import_path5.default.join(import_os.default.tmpdir(), `coc-${v4_default()}`);
6411
+ const currentFile = import_path5.default.join(import_os.default.tmpdir(), `coc-${v4_default()}`);
6412
+ let output;
6307
6413
  try {
6308
- await this.git.exec(this.repo.root, ["apply", "--cached", "--unidiff-zero", "-"], { input: lines.join("\n") });
6309
- this.refresh();
6310
- } catch (e) {
6311
- this.channel.appendLine(`[Error] ${e.message}`);
6414
+ await import_util2.default.promisify(import_fs2.default.writeFile)(stagedFile, base, "utf8");
6415
+ await import_util2.default.promisify(import_fs2.default.writeFile)(currentFile, content, "utf8");
6416
+ const result = await this.exec([
6417
+ "--no-pager",
6418
+ "diff",
6419
+ "--no-index",
6420
+ "--no-ext-diff",
6421
+ "-p",
6422
+ "-U0",
6423
+ "--no-color",
6424
+ stagedFile,
6425
+ currentFile
6426
+ ], { allowedExitCodes: [1] });
6427
+ output = result.stdout;
6428
+ } finally {
6429
+ await Promise.all([
6430
+ import_util2.default.promisify(import_fs2.default.unlink)(stagedFile).catch(() => void 0),
6431
+ import_util2.default.promisify(import_fs2.default.unlink)(currentFile).catch(() => void 0)
6432
+ ]);
6312
6433
  }
6434
+ if (!output) return [];
6435
+ this.channel.appendLine("> git diff buffer contents");
6436
+ const lines = output.replace(/\r?\n$/, "").split(/\r?\n/);
6437
+ return parseDiff(lines);
6313
6438
  }
6314
- async chunkUnstage() {
6315
- var _a;
6316
- let { nvim } = import_coc11.workspace;
6317
- const { diffs } = this;
6318
- let line = await nvim.call("line", ".");
6319
- let adjust = 0;
6320
- let invalid = false;
6321
- for (let diff of diffs) {
6322
- if (diff.end >= line) {
6323
- if (diff.start <= line && diff.changeType != "delete" /* Delete */) {
6324
- import_coc11.window.showErrorMessage(`Current line contains unstaged change.`);
6325
- invalid = true;
6326
- }
6327
- break;
6328
- }
6329
- adjust -= diff.added.count;
6330
- adjust += diff.removed.count;
6331
- }
6332
- if (invalid) return;
6333
- line = line + adjust;
6334
- let stagedDiff = await this.repo.getStagedChunks(this.relpath);
6335
- let chunks = (_a = Object.values(stagedDiff)[0]) != null ? _a : [];
6336
- if (!chunks.length) {
6337
- import_coc11.window.showErrorMessage(`Staged chunk not found`);
6338
- return;
6339
- }
6340
- let chunk = chunks.find((o) => chunkContainsLine(o, line));
6341
- if (!chunk) {
6342
- import_coc11.window.showErrorMessage(`Unable to find staged chunk on current line`);
6343
- return;
6344
- }
6345
- this.channel.appendLine(`[Info] resolved chunk ${JSON.stringify(chunk, null, 2)}`);
6346
- let patch = createUnstagePatch(this.relpath, chunk);
6347
- if (!patch) return;
6439
+ async getFileContent(relpath, revision, encoding = "utf8") {
6348
6440
  try {
6349
- await this.git.exec(this.repo.root, ["apply", "--cached", "--unidiff-zero", "-"], { input: patch });
6350
- this.refresh();
6351
- } catch (e) {
6352
- import_coc11.window.showErrorMessage(`Unable to apply patch: ${e.message}`);
6353
- this.channel.appendLine(`[Error] ${e.message}`);
6441
+ const object = revision.endsWith(":") ? revision : `${revision}:`;
6442
+ const result = await this.exec(["--no-pager", "show", `${object}${toUnixSlash(relpath)}`], {
6443
+ encoding,
6444
+ log: false,
6445
+ allowedExitCodes: [128]
6446
+ });
6447
+ if (result.exitCode !== 0) return "";
6448
+ return result.stdout.replace(/\r?\n$/, "").split(/\r?\n/).join("\n");
6449
+ } catch (_e) {
6450
+ return "";
6354
6451
  }
6355
6452
  }
6356
- async nextChunk() {
6357
- const { diffs } = this;
6358
- let { nvim } = import_coc11.workspace;
6359
- if (!diffs || diffs.length == 0) return;
6360
- let line = await nvim.call("line", ".");
6361
- for (let diff of diffs) {
6362
- if (diff.start > line) {
6363
- await import_coc11.window.moveTo({ line: Math.max(diff.start - 1, 0), character: 0 });
6364
- return;
6365
- }
6366
- }
6367
- if (await nvim.getOption("wrapscan")) {
6368
- await import_coc11.window.moveTo({ line: Math.max(diffs[0].start - 1, 0), character: 0 });
6453
+ async getIndexIdentity() {
6454
+ try {
6455
+ const gitPath = (await this.safeRun(["rev-parse", "--git-path", "index"])).trim();
6456
+ if (!gitPath) return "";
6457
+ const indexPath = import_path5.default.isAbsolute(gitPath) ? gitPath : import_path5.default.join(this.root, gitPath);
6458
+ const stat = await import_util2.default.promisify(import_fs2.default.stat)(indexPath);
6459
+ return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
6460
+ } catch (_e) {
6461
+ return "";
6369
6462
  }
6370
6463
  }
6371
- async prevChunk() {
6372
- const { nvim } = import_coc11.workspace;
6373
- let { diffs } = this;
6374
- let line = await nvim.call("line", ".");
6375
- if (!diffs || diffs.length == 0) return;
6376
- for (let diff of diffs.slice().reverse()) {
6377
- if (diff.end < line) {
6378
- await import_coc11.window.moveTo({ line: Math.max(diff.start - 1, 0), character: 0 });
6379
- return;
6464
+ async getHeadIdentity() {
6465
+ return this.safeRun(["rev-parse", "--verify", "HEAD"]);
6466
+ }
6467
+ async getDiffAll(category) {
6468
+ let diffGroups = /* @__PURE__ */ new Map();
6469
+ let args = ["-c", "core.quotepath=false", "--no-pager", "diff", "--no-ext-diff", "--no-renames", "-p", "-U0", "--no-color"];
6470
+ if (category === 0 /* All */) {
6471
+ const head = await this.safeRun(["rev-parse", "--verify", "HEAD"]);
6472
+ if (head) {
6473
+ args.push("HEAD");
6474
+ } else {
6475
+ const emptyTree = await this.exec(["hash-object", "-t", "tree", "--stdin"], { input: "", log: false });
6476
+ args.push(emptyTree.stdout.trim());
6380
6477
  }
6478
+ } else if (category === 1 /* Staged */) {
6479
+ args.push("--cached");
6381
6480
  }
6382
- if (await nvim.getOption("wrapscan")) {
6383
- await import_coc11.window.moveTo({ line: Math.max(diffs[diffs.length - 1].start - 1, 0), character: 0 });
6384
- }
6385
- }
6386
- async chunkInfo() {
6387
- let line = await import_coc11.workspace.nvim.call("line", ".");
6388
- let diff = this.getChunk(line);
6389
- if (diff) {
6390
- let content = diff.head + "\n" + diff.lines.join("\n");
6391
- await this.showDoc(content, "diff");
6392
- } else {
6393
- let chunks = [];
6394
- try {
6395
- let stagedDiff = await this.repo.getStagedChunks(this.relpath);
6396
- chunks = Object.values(stagedDiff)[0];
6397
- } catch (e) {
6481
+ let output = (await this.exec(args)).stdout;
6482
+ if (!output) return diffGroups;
6483
+ const lines = output.replace(/\r?\n$/, "").split(/\r?\n/);
6484
+ let lineGroups = /* @__PURE__ */ new Map();
6485
+ let file = null;
6486
+ for (const line of lines) {
6487
+ if (line.startsWith("diff --git")) {
6488
+ file = parseDiffPath(line) || null;
6398
6489
  }
6399
- let adjust = 0;
6400
- for (let diff2 of this.diffs) {
6401
- if (diff2.end >= line) {
6402
- break;
6490
+ if (file) {
6491
+ if (!lineGroups.has(file)) {
6492
+ lineGroups.set(file, []);
6403
6493
  }
6404
- adjust -= diff2.added.count;
6405
- adjust += diff2.removed.count;
6494
+ lineGroups.get(file).push(line);
6406
6495
  }
6407
- line = line + adjust;
6408
- let chunk = chunks.find((o) => chunkContainsLine(o, line));
6409
- if (chunk) {
6410
- let content = "Staged changes\n" + chunk.lines.join("\n");
6411
- await this.showDoc(content, "diff");
6412
- } else {
6413
- await this.showCommit(true);
6496
+ }
6497
+ for (const [file2, lines2] of lineGroups) {
6498
+ let diffs = parseDiff(lines2);
6499
+ if (diffs) {
6500
+ diffGroups.set(file2, diffs);
6414
6501
  }
6415
6502
  }
6503
+ return diffGroups;
6416
6504
  }
6417
- allChunkInfo() {
6418
- return this.diffs ? this.diffs.slice() : [];
6505
+ async isIgnored(relativePath) {
6506
+ let res = await this.exec(["check-ignore", "-q", "--", relativePath], { allowedExitCodes: [1] });
6507
+ return res.exitCode === 0;
6419
6508
  }
6420
- async showBlameInfo(lnum) {
6421
- if (this._disposed) return;
6422
- let { nvim } = import_coc11.workspace;
6423
- let { virtualTextSrcId, addGBlameToBufferVar, addGBlameToVirtualText } = this.config;
6424
- if (!this.showBlame) return;
6425
- let infos = this.blameInfo;
6426
- if (!infos) return;
6427
- let blameText;
6428
- if (infos.length == 0) {
6429
- blameText = "File not indexed";
6430
- } else {
6431
- let info = infos.find((o) => lnum >= o.startLnum && lnum <= o.endLnum);
6432
- if (info && info.author && info.author != "Not Committed Yet") {
6433
- blameText = formatBlameText(info, this.config.blameFormat);
6434
- } else {
6435
- blameText = "Not committed yet";
6436
- }
6437
- }
6438
- let buffer = nvim.createBuffer(this.doc.bufnr);
6439
- let hide_blame = await nvim.getVar("coc_git_hide_blame_virtual_text");
6440
- if (hide_blame) {
6441
- buffer.clearNamespace(virtualTextSrcId);
6442
- } else {
6443
- if (addGBlameToBufferVar) {
6444
- nvim.pauseNotification();
6445
- buffer.setVar("coc_git_blame", blameText, true);
6446
- nvim.call("coc#util#do_autocmd", ["CocGitStatusChange"], true);
6447
- nvim.resumeNotification(false, true);
6448
- }
6449
- if (addGBlameToVirtualText) {
6450
- const prefix = this.config.virtualTextPrefix;
6451
- nvim.pauseNotification();
6452
- buffer.clearNamespace(virtualTextSrcId);
6453
- buffer.setVirtualText(virtualTextSrcId, lnum - 1, [[prefix + blameText, "CocCodeLens"]]);
6454
- nvim.resumeNotification(true, true);
6455
- }
6456
- }
6509
+ async hasConflicts(relativePath) {
6510
+ let indexed = await this.isIndexed(relativePath);
6511
+ if (!indexed) return false;
6512
+ let res = await this.exec(["diff", "--staged", "--name-status", "--", relativePath]);
6513
+ return res.stdout.trim().startsWith("U");
6457
6514
  }
6458
- async showBlameDoc(lnum) {
6459
- let indexed = await this.repo.isIndexed(this.relpath);
6460
- if (!indexed) {
6461
- import_coc11.window.showWarningMessage("File not indexed");
6462
- } else if (await this.repo.isShallow()) {
6463
- import_coc11.window.showWarningMessage("Shallow repository, blame not available");
6464
- } else {
6465
- let infos = await this.getBlameInfo([lnum, lnum]);
6466
- let info = infos.find((o) => lnum >= o.startLnum && lnum <= o.endLnum);
6467
- if (info && info.author && info.author != "Not Committed Yet") {
6468
- let blameText = [];
6469
- blameText.push(`${info.author}, ${info.time}`);
6470
- blameText.push(`${info.summary}`);
6471
- blameText.push(`${info.sha.substring(0, 7)}`);
6472
- await this.showDoc(blameText.join("\n\n"), "text");
6473
- } else {
6474
- import_coc11.window.showWarningMessage("Not committed yet");
6475
- }
6515
+ async isIndexed(relpath) {
6516
+ let res = await this.exec(["ls-files", "--", relpath]);
6517
+ return res.stdout && res.stdout.trim().length > 0;
6518
+ }
6519
+ async getUsername() {
6520
+ if (typeof this.userName === "string") return this.userName;
6521
+ try {
6522
+ let res = await this.exec(["config", "user.name"]);
6523
+ this.userName = res.stdout.trim();
6524
+ return this.userName;
6525
+ } catch (e) {
6526
+ this.userName = "";
6527
+ return "";
6476
6528
  }
6477
6529
  }
6478
- async diffDocument(force = false) {
6479
- let { nvim } = import_coc11.workspace;
6480
- let revision = this.config.diffRevision;
6481
- const { bufnr } = this.doc;
6482
- let content = this.doc.content;
6483
- let eol = this.doc.textDocument["eol"];
6484
- let encoding = await this.doc.buffer.getOption("fileencoding");
6485
- const diffs = await this.repo.getDiff(this.relpath, eol ? content : content + "\n", revision, encoding || "utf8");
6486
- if (diffs == null || this._disposed) return;
6487
- if (diffs.length === 0) {
6488
- this.currentSigns = [];
6489
- this.diffs = [];
6490
- this.setBufferStatus("");
6491
- if (this.config.enableGutters) {
6492
- nvim.call("sign_unplace", [signGroup, { buffer: bufnr }], true);
6493
- nvim.redrawVim();
6494
- }
6495
- return;
6496
- }
6497
- if (equals(diffs, this.diffs)) {
6498
- return;
6499
- }
6500
- this.diffs = diffs;
6501
- let added = 0;
6502
- let changed = 0;
6503
- let removed = 0;
6504
- let signs = [];
6505
- for (let diff of diffs) {
6506
- if (diff.changeType == "add" /* Add */) {
6507
- added += diff.added.count;
6508
- } else if (diff.changeType == "delete" /* Delete */) {
6509
- removed += diff.removed.count;
6510
- } else if (diff.changeType == "changed" /* Change */) {
6511
- let [add, remove] = [diff.added.count, diff.removed.count];
6512
- let min = Math.min(add, remove);
6513
- changed += min;
6514
- added += add - min;
6515
- removed += remove - min;
6516
- }
6517
- let { start, end } = diff;
6518
- for (let i = start; i <= end; i++) {
6519
- let topdelete = diff.changeType == "delete" /* Delete */ && i == 0;
6520
- let changedelete = diff.changeType == "changed" /* Change */ && diff.removed.count > diff.added.count && i == end;
6521
- signs.push({
6522
- changeType: topdelete ? "topdelete" : changedelete ? "changedelete" : diff.changeType,
6523
- lnum: topdelete ? 1 : i
6524
- });
6525
- }
6526
- if (diff.changeType == "changed" /* Change */) {
6527
- let [add, remove] = [diff.added.count, diff.removed.count];
6528
- if (add > remove) {
6529
- for (let i = 0; i < add - remove; i++) {
6530
- signs.push({
6531
- changeType: "add" /* Add */,
6532
- lnum: diff.end + 1 + i
6533
- });
6534
- }
6535
- }
6536
- }
6537
- }
6538
- let items = [];
6539
- if (added) items.push(`+${added}`);
6540
- if (changed) items.push(`~${changed}`);
6541
- if (removed) items.push(`-${removed}`);
6542
- let status = ` ${items.join(" ")} `;
6543
- this.setBufferStatus(status);
6544
- this.currentSigns = signs;
6545
- if (!this.config.realtimeGutters && !force) return;
6546
- this.updateGutters();
6547
- }
6548
- updateGutters() {
6549
- if (this._disposed) return;
6550
- if (!this.config.enableGutters) return;
6551
- let { nvim } = import_coc11.workspace;
6552
- let { bufnr } = this.doc;
6553
- let { signPriority } = this.config;
6554
- let signs = this.currentSigns;
6555
- nvim.pauseNotification();
6556
- nvim.call("sign_unplace", [signGroup, { buffer: bufnr }], true);
6557
- for (let sign of signs) {
6558
- let name = this.getSignName(sign.changeType);
6559
- nvim.call("sign_place", [0, signGroup, name, bufnr, { lnum: sign.lnum, priority: signPriority }], true);
6530
+ async isShallow() {
6531
+ try {
6532
+ let res = await this.exec(["rev-parse", "--is-shallow-repository"]);
6533
+ return res.stdout.trim() === "true";
6534
+ } catch (e) {
6535
+ return false;
6560
6536
  }
6561
- nvim.resumeNotification(true, true);
6562
6537
  }
6563
- async loadBlames() {
6564
- if (!this.showBlame) return;
6565
- let result = [];
6566
- let indexed = await this.repo.isIndexed(this.relpath);
6567
- if (indexed) result = await this.getBlameInfo();
6568
- if (this._disposed) return;
6569
- this.blameInfo = result;
6538
+ async exec(args, options = {}) {
6539
+ return await this.git.exec(this.root, args, options);
6570
6540
  }
6571
- async getBlameInfo(range) {
6572
- let { relpath } = this;
6573
- let root = this.repo.root;
6574
- let res = [];
6575
- const useRealTime = this.config.blameUseRealTime;
6541
+ async safeRun(args, options = {}) {
6576
6542
  try {
6577
- let currentAuthor = await this.repo.getUsername();
6578
- const args = ["--no-pager", "blame", "-w", "-b", "-p", "--incremental", "--root", "--date", "relative", "--contents", "-"];
6579
- if (range) args.push("-L", range.join(","));
6580
- args.push("--", relpath);
6581
- let r = await this.git.exec(root, args, {
6582
- log: false,
6583
- input: this.doc.content
6584
- });
6585
- if (!r.stdout) return res;
6586
- let info;
6587
- const commits = /* @__PURE__ */ new Map();
6588
- for (let line of r.stdout.trim().split(/\r?\n/)) {
6589
- line = line.trim();
6590
- if (/^(author |committer )?External file \(--contents\)/.test(line)) {
6591
- line = "Not committed yet.";
6592
- }
6593
- let ms = line.match(/^([A-Za-z0-9]+)\s(\d+)\s(\d+)\s(\d+)/);
6594
- if (ms) {
6595
- let startLnum = parseInt(ms[3], 10);
6596
- info = { startLnum, sha: ms[1], endLnum: startLnum + parseInt(ms[4], 10) - 1, index: ms[2] };
6597
- if (!/^0+$/.test(ms[1])) {
6598
- let find = commits.get(ms[1]);
6599
- if (find) {
6600
- info.author = find.author;
6601
- info.time = find.time;
6602
- info.summary = find.summary;
6603
- } else {
6604
- commits.set(ms[1], info);
6605
- }
6606
- }
6607
- res.push(info);
6608
- } else if (info) {
6609
- if (line.startsWith("author ")) {
6610
- let author = line.replace(/^author/, "").trim();
6611
- info.author = author == currentAuthor ? "You" : author;
6612
- } else if (line.startsWith("author-time ")) {
6613
- let text = line.replace(/^author-time/, "").trim();
6614
- const timestamps = parseInt(text, 10) * 1e3;
6615
- info.time = useRealTime ? new Date(timestamps).toLocaleString() : format(timestamps, process.env.LANG);
6616
- } else if (line.startsWith("summary ")) {
6617
- let text = line.replace(/^summary/, "").trim();
6618
- info.summary = text;
6619
- }
6620
- }
6621
- }
6622
- return res;
6543
+ let res = await this.exec(args, options);
6544
+ return res ? res.stdout.replace(/\s*$/, "") : "";
6623
6545
  } catch (e) {
6624
- this.channel.appendLine(e.stack);
6625
- }
6626
- return res;
6627
- }
6628
- async diffCached() {
6629
- let res = await this.repo.safeRun(["diff", "--cached"]);
6630
- if (!res.trim()) {
6631
- import_coc11.window.showWarningMessage("Empty diff");
6632
- return;
6546
+ return "";
6633
6547
  }
6634
- let { nvim } = import_coc11.workspace;
6635
- nvim.pauseNotification();
6636
- nvim.command(`keepalt above new +setl\\ previewwindow`, true);
6637
- nvim.call("append", [0, res.split(/\r?\n/)], true);
6638
- nvim.command("normal! Gdd", true);
6639
- nvim.command(`exe 1`, true);
6640
- nvim.command("setfiletype git", true);
6641
- nvim.command("setl buftype=nofile nomodifiable bufhidden=wipe nobuflisted", true);
6642
- await nvim.resumeNotification();
6643
6548
  }
6644
- async nextConflict() {
6645
- let { nvim } = import_coc11.workspace;
6646
- if (!this.conflicts.length) {
6647
- import_coc11.window.showWarningMessage("No conflicts detected");
6648
- return;
6549
+ };
6550
+ function readQuotedGitPath(input, start) {
6551
+ if (input[start] !== '"') return void 0;
6552
+ let value = "";
6553
+ for (let index = start + 1; index < input.length; index++) {
6554
+ const character = input[index];
6555
+ if (character === '"') return { value, end: index + 1 };
6556
+ if (character !== "\\") {
6557
+ value += character;
6558
+ continue;
6649
6559
  }
6650
- let line = await nvim.call("line", ".");
6651
- for (let conflict of this.conflicts) {
6652
- if (conflict.start > line) {
6653
- await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
6654
- return;
6655
- }
6560
+ const escaped = input[++index];
6561
+ if (escaped == null) return void 0;
6562
+ const escapes = {
6563
+ a: "\x07",
6564
+ b: "\b",
6565
+ t: " ",
6566
+ n: "\n",
6567
+ v: "\v",
6568
+ f: "\f",
6569
+ r: "\r",
6570
+ '"': '"',
6571
+ "\\": "\\"
6572
+ };
6573
+ if (escapes[escaped] != null) {
6574
+ value += escapes[escaped];
6575
+ continue;
6656
6576
  }
6657
- if (await nvim.getOption("wrapscan")) {
6658
- await import_coc11.window.moveTo({ line: Math.max(this.conflicts[0].start - 1, 0), character: 0 });
6577
+ if (/[0-7]/.test(escaped)) {
6578
+ let octal = escaped;
6579
+ while (octal.length < 3 && /[0-7]/.test(input[index + 1] || "")) octal += input[++index];
6580
+ value += String.fromCharCode(parseInt(octal, 8));
6581
+ continue;
6659
6582
  }
6583
+ value += escaped;
6660
6584
  }
6661
- async prevConflict() {
6662
- let { nvim } = import_coc11.workspace;
6663
- if (!this.conflicts.length) {
6664
- import_coc11.window.showWarningMessage("No conflicts detected", "warning");
6665
- return;
6666
- }
6667
- let line = await nvim.call("line", ".");
6668
- let conflict = getPreviousConflict(this.conflicts, line);
6669
- if (conflict) {
6670
- await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
6671
- return;
6672
- }
6673
- if (await nvim.getOption("wrapscan")) {
6674
- conflict = this.conflicts[this.conflicts.length - 1];
6675
- await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
6676
- }
6585
+ return void 0;
6586
+ }
6587
+ function parseDiffPath(line) {
6588
+ const prefix = "diff --git ";
6589
+ if (!line.startsWith(prefix)) return void 0;
6590
+ const value = line.slice(prefix.length);
6591
+ if (value.startsWith('"')) {
6592
+ const first = readQuotedGitPath(value, 0);
6593
+ if (!first) return void 0;
6594
+ const secondStart = value.indexOf('"', first.end);
6595
+ const second = secondStart === -1 ? void 0 : readQuotedGitPath(value, secondStart);
6596
+ if (!second || !first.value.startsWith("a/") || !second.value.startsWith("b/")) return void 0;
6597
+ const firstPath = first.value.slice(2);
6598
+ return firstPath === second.value.slice(2) ? firstPath : void 0;
6677
6599
  }
6678
- async conflictKeepPart(part) {
6679
- const { nvim } = import_coc11.workspace;
6680
- let conflicts = this.conflicts;
6681
- if (!conflicts || conflicts.length == 0) {
6682
- import_coc11.window.showWarningMessage("No conflicts detected");
6683
- return;
6600
+ if (!value.startsWith("a/")) return void 0;
6601
+ const paths = value.slice(2);
6602
+ let separator = paths.indexOf(" b/");
6603
+ while (separator !== -1) {
6604
+ const firstPath = paths.slice(0, separator);
6605
+ if (firstPath === paths.slice(separator + 3)) return firstPath;
6606
+ separator = paths.indexOf(" b/", separator + 1);
6607
+ }
6608
+ return void 0;
6609
+ }
6610
+ var repo_default = Repo;
6611
+ function parseDiff(diffLines) {
6612
+ const allLines = diffLines.slice(4);
6613
+ const diffs = [];
6614
+ let diff = null;
6615
+ for (const line of allLines) {
6616
+ if (!line.startsWith("@@")) {
6617
+ if (diff) {
6618
+ diff.lines.push(line);
6619
+ }
6620
+ continue;
6684
6621
  }
6685
- let line = await nvim.call("line", ".");
6686
- for (let conflict of conflicts) {
6687
- if (conflict.start <= line && conflict.end >= line) {
6688
- switch (part) {
6689
- case 0 /* Current */:
6690
- let start = conflict.common ? conflict.common : conflict.sep;
6691
- await nvim.command(`${start},${conflict.end}d | ${conflict.start}d`);
6692
- return;
6693
- case 1 /* Incoming */:
6694
- await nvim.command(`${conflict.end}d | ${conflict.start},${conflict.sep}d`);
6695
- return;
6696
- case 2 /* Both */:
6697
- if (conflict.common) {
6698
- await nvim.command(`${conflict.end}d | ${conflict.common},${conflict.sep}d | ${conflict.start}d`);
6699
- } else {
6700
- await nvim.command(`${conflict.end}d | ${conflict.sep}d | ${conflict.start}d`);
6701
- }
6702
- return;
6703
- }
6704
- }
6622
+ let diffKey = line.split("@@", 2)[1].trim();
6623
+ const [pres, nows] = diffKey.split(/\s+/).map((str) => str.slice(1).split(","));
6624
+ const removed = {
6625
+ start: parseInt(pres[0], 10),
6626
+ count: parseInt(`${pres[1] || 1}`, 10)
6627
+ };
6628
+ const added = {
6629
+ start: parseInt(nows[0], 10),
6630
+ count: parseInt(`${nows[1] || 1}`, 10)
6631
+ };
6632
+ if (added.count === 0) {
6633
+ diff = {
6634
+ lines: [],
6635
+ start: added.start,
6636
+ end: added.start,
6637
+ head: line,
6638
+ removed,
6639
+ added,
6640
+ changeType: "delete" /* Delete */
6641
+ };
6642
+ diffs.push(diff);
6643
+ } else if (removed.count === 0) {
6644
+ diff = {
6645
+ lines: [],
6646
+ start: added.start,
6647
+ end: added.start + added.count - 1,
6648
+ head: line,
6649
+ removed,
6650
+ added,
6651
+ changeType: "add" /* Add */
6652
+ };
6653
+ diffs.push(diff);
6654
+ } else {
6655
+ diff = {
6656
+ lines: [],
6657
+ start: added.start,
6658
+ end: added.start + Math.min(added.count, removed.count) - 1,
6659
+ head: line,
6660
+ removed,
6661
+ added,
6662
+ changeType: "changed" /* Change */
6663
+ };
6664
+ diffs.push(diff);
6705
6665
  }
6706
- import_coc11.window.showWarningMessage("Not positioned on a conflict");
6707
6666
  }
6708
- async browser(action = "open", range, permalink = false) {
6709
- let { nvim } = import_coc11.workspace;
6710
- let config = import_coc11.workspace.getConfiguration("git");
6711
- let head = (await this.repo.safeRun(["rev-parse", "HEAD"])).trim();
6712
- let branch = config.get("browserBranchName", "").trim();
6713
- if (!branch.length) {
6714
- branch = (await this.repo.safeRun(["symbolic-ref", "--short", "-q", "HEAD"])).trim();
6715
- }
6716
- let lines = range && range.length == 2 ? [
6717
- range[0],
6718
- range[1]
6719
- ] : [await nvim.eval('line(".")')];
6720
- if (this.doc.filetype == "markdown") {
6721
- let line = await nvim.call("getline", ["."]);
6722
- if (line.startsWith("#")) {
6723
- let words = line.replace(/^#+\s*/, "").split(/\s+/);
6724
- lines = words.map((s) => s.toLowerCase()).join("-");
6725
- }
6726
- }
6727
- let output = await this.repo.safeRun(["remote"]);
6728
- if (!output.trim()) {
6729
- import_coc11.window.showWarningMessage(`No remote found`);
6730
- return;
6667
+ return diffs;
6668
+ }
6669
+
6670
+ // src/model/staged.ts
6671
+ function changeKind(diff) {
6672
+ if (diff.changeType === "add") return "add";
6673
+ if (diff.changeType === "delete") return diff.start === 0 ? "topDelete" : "delete";
6674
+ return diff.removed.count > diff.added.count ? "changeDelete" : "change";
6675
+ }
6676
+ function changesFromDiffs(diffs, layer) {
6677
+ return diffs.map((diff) => ({
6678
+ kind: changeKind(diff),
6679
+ layer,
6680
+ line: diff.start,
6681
+ endLine: diff.end,
6682
+ sourceLine: diff.removed.start,
6683
+ sourceEndLine: diff.removed.start + diff.removed.count - 1,
6684
+ sourceCount: diff.removed.count,
6685
+ targetCount: diff.added.count
6686
+ }));
6687
+ }
6688
+ function createHunkMapping(indexLines, bufferLines, changes) {
6689
+ const hunks = changes.filter((change) => change.sourceLine != null && change.sourceCount != null && change.targetCount != null).map((change) => ({
6690
+ oldStart: change.sourceLine,
6691
+ oldCount: change.sourceCount,
6692
+ newStart: change.line,
6693
+ newCount: change.targetCount
6694
+ })).sort((a, b) => a.oldStart - b.oldStart || a.newStart - b.newStart);
6695
+ if (hunks.length === 0) return void 0;
6696
+ const indexToBuffer = Array(indexLines.length);
6697
+ const insertionAnchors = /* @__PURE__ */ new Map();
6698
+ let oldCursor = 1;
6699
+ let newCursor = 1;
6700
+ for (const hunk of hunks) {
6701
+ if (hunk.oldStart < oldCursor) continue;
6702
+ const unchanged = hunk.oldStart - oldCursor;
6703
+ for (let index = 0; index < unchanged; index++) {
6704
+ const oldLine = oldCursor + index;
6705
+ const newLine = newCursor + index;
6706
+ if (oldLine <= indexLines.length && newLine <= bufferLines.length) indexToBuffer[oldLine - 1] = newLine;
6707
+ }
6708
+ const anchor = Math.max(1, Math.min(bufferLines.length || 1, hunk.newStart || newCursor));
6709
+ insertionAnchors.set(hunk.oldStart, anchor);
6710
+ for (let index = 0; index < hunk.oldCount; index++) {
6711
+ const oldLine = hunk.oldStart + index;
6712
+ if (oldLine > indexLines.length) break;
6713
+ if (index < hunk.newCount) {
6714
+ const newLine = hunk.newStart + index;
6715
+ if (newLine >= 1 && newLine <= bufferLines.length) indexToBuffer[oldLine - 1] = newLine;
6716
+ }
6717
+ }
6718
+ oldCursor = hunk.oldStart + hunk.oldCount;
6719
+ newCursor = hunk.newStart + hunk.newCount;
6720
+ }
6721
+ for (let index = oldCursor; index <= indexLines.length; index++) {
6722
+ const newLine = newCursor + index - oldCursor;
6723
+ if (newLine <= bufferLines.length) indexToBuffer[index - 1] = newLine;
6724
+ }
6725
+ return { indexToBuffer, insertionAnchors };
6726
+ }
6727
+ function createLineMapping(indexLines, bufferLines, unstagedChanges) {
6728
+ const fromHunks = createHunkMapping(indexLines, bufferLines, unstagedChanges);
6729
+ if (fromHunks) return fromHunks;
6730
+ if (unstagedChanges.length === 0) {
6731
+ return {
6732
+ indexToBuffer: indexLines.map((_, index) => index + 1 <= bufferLines.length ? index + 1 : void 0),
6733
+ insertionAnchors: /* @__PURE__ */ new Map()
6734
+ };
6735
+ }
6736
+ const indexToBuffer = Array(indexLines.length);
6737
+ const insertionAnchors = /* @__PURE__ */ new Map();
6738
+ const rows = indexLines.length + 1;
6739
+ const cols = bufferLines.length + 1;
6740
+ const table = Array.from({ length: rows }, () => Array(cols).fill(0));
6741
+ for (let i2 = indexLines.length - 1; i2 >= 0; i2--) {
6742
+ for (let j2 = bufferLines.length - 1; j2 >= 0; j2--) {
6743
+ table[i2][j2] = indexLines[i2] === bufferLines[j2] ? table[i2 + 1][j2 + 1] + 1 : Math.max(table[i2 + 1][j2], table[i2][j2 + 1]);
6744
+ }
6745
+ }
6746
+ let i = 0;
6747
+ let j = 0;
6748
+ while (i < indexLines.length && j < bufferLines.length) {
6749
+ if (indexLines[i] === bufferLines[j]) {
6750
+ indexToBuffer[i] = j + 1;
6751
+ i++;
6752
+ j++;
6753
+ } else if (table[i + 1][j] >= table[i][j + 1]) {
6754
+ i++;
6755
+ } else {
6756
+ insertionAnchors.set(i + 1, j + 1);
6757
+ j++;
6731
6758
  }
6732
- let names = output.trim().split(/\r?\n/);
6733
- let browserRemoteName = config.get("browserRemoteName", "").trim();
6734
- if (browserRemoteName.length > 0) {
6735
- if (names.includes(browserRemoteName)) {
6736
- names = [browserRemoteName];
6737
- } else {
6738
- import_coc11.window.showWarningMessage("Configured git.browserRemoteName missing from remote list");
6739
- return;
6740
- }
6759
+ }
6760
+ if (i < indexLines.length) insertionAnchors.set(i + 1, Math.max(1, Math.min(bufferLines.length || 1, j + 1)));
6761
+ return { indexToBuffer, insertionAnchors };
6762
+ }
6763
+ function resolveMappedLine(line, mapping, bufferLineCount) {
6764
+ const direct = line > 0 ? mapping.indexToBuffer[line - 1] : void 0;
6765
+ if (direct != null) return direct;
6766
+ const anchor = mapping.insertionAnchors.get(line);
6767
+ if (anchor != null) return Math.max(1, Math.min(bufferLineCount || 1, anchor));
6768
+ if (bufferLineCount === 0) return 1;
6769
+ if (line <= 0) return 1;
6770
+ for (let index = Math.min(line - 1, mapping.indexToBuffer.length - 1); index >= 0; index--) {
6771
+ const mapped = mapping.indexToBuffer[index];
6772
+ if (mapped != null) return Math.min(bufferLineCount, mapped + line - index - 1);
6773
+ }
6774
+ return Math.min(bufferLineCount, line);
6775
+ }
6776
+ function mapIndexChangesToBuffer(stagedChanges, mapping, bufferLineCount) {
6777
+ return stagedChanges.map((change) => {
6778
+ var _a;
6779
+ const isDeletion = change.kind === "delete" || change.kind === "topDelete";
6780
+ const sourceLine = isDeletion && change.sourceLine != null ? change.sourceLine : change.line;
6781
+ const sourceEndLine = isDeletion && change.sourceEndLine != null ? change.sourceEndLine : (_a = change.endLine) != null ? _a : change.line;
6782
+ const line = resolveMappedLine(sourceLine, mapping, bufferLineCount);
6783
+ const endLine = Math.max(line, resolveMappedLine(sourceEndLine, mapping, bufferLineCount));
6784
+ return { ...change, line, endLine };
6785
+ });
6786
+ }
6787
+ function gutterSignsFromChanges(changes) {
6788
+ var _a, _b, _c;
6789
+ const result = [];
6790
+ for (const change of changes) {
6791
+ const start = change.line === 0 ? 1 : Math.max(1, change.line);
6792
+ const end = Math.max(start, (_a = change.endLine) != null ? _a : start);
6793
+ if (change.kind === "delete" || change.kind === "topDelete") {
6794
+ result.push({ line: start, kind: change.kind, layer: change.layer });
6795
+ continue;
6741
6796
  }
6742
- let urls = [];
6743
- for (let name of names) {
6744
- let uri = await this.repo.safeRun(["config", "--get", `remote.${name}.url`]);
6745
- if (!uri.length) continue;
6746
- let repoURL = getRepoUrl(uri);
6747
- if (!repoURL) continue;
6748
- let tmp;
6749
- try {
6750
- tmp = new import_url.URL(repoURL);
6751
- } catch (_e) {
6752
- continue;
6753
- }
6754
- let hostname = tmp.hostname;
6755
- let fix = "|";
6756
- try {
6757
- fix = config.get("urlFix")[hostname][permalink ? 1 : 0];
6758
- } catch (e) {
6759
- }
6760
- let url = getUrl(fix, repoURL, permalink ? head : branch || head, toUnixSlash(this.relpath), lines);
6761
- if (url) urls.push(url);
6797
+ for (let line = start; line <= end; line++) {
6798
+ result.push({ line, kind: line === end && change.kind === "changeDelete" ? "changeDelete" : change.kind, layer: change.layer });
6762
6799
  }
6763
- if (urls.length == 1) {
6764
- if (action == "open") {
6765
- await import_coc11.workspace.openResource(urls[0]);
6766
- } else {
6767
- nvim.call("setreg", ["+", urls[0]], true);
6768
- import_coc11.window.showInformationMessage("Copied url to clipboard");
6769
- }
6770
- } else if (urls.length > 1) {
6771
- let url = await import_coc11.window.showQuickPick(urls, { canPickMany: false, title: "Pick remote url" });
6772
- if (url) {
6773
- if (action == "open") {
6774
- await import_coc11.workspace.openResource(url);
6775
- } else {
6776
- nvim.call("setreg", ["+", url], true);
6777
- nvim.call("setreg", ["*", url], true);
6778
- import_coc11.window.showInformationMessage("Copied url to clipboard");
6779
- }
6800
+ if (change.kind === "change" && ((_b = change.targetCount) != null ? _b : 0) > ((_c = change.sourceCount) != null ? _c : 0)) {
6801
+ const extra = change.targetCount - change.sourceCount;
6802
+ for (let index = 0; index < extra; index++) {
6803
+ result.push({ line: end + 1 + index, kind: "add", layer: change.layer });
6780
6804
  }
6781
6805
  }
6782
6806
  }
6783
- // show commit of current line in split window
6784
- async showCommit(useFloating = false) {
6785
- let indexed = await this.repo.isIndexed(this.relpath);
6786
- if (!indexed) {
6787
- import_coc11.window.showWarningMessage(`"${this.relpath}" not indexed.`);
6788
- return;
6789
- }
6790
- let nvim = import_coc11.workspace.nvim;
6791
- let line = await nvim.eval('line(".")');
6792
- let args = ["--no-pager", "blame", "-w", "-l", "--root", "-t", `-L${line},${line}`, "--", this.relpath];
6793
- let res = await this.repo.exec(args);
6794
- let output = res.stdout.trim();
6795
- if (!output.length) return;
6796
- let commit = output.match(/^\S+/)[0];
6797
- if (/^0+$/.test(commit)) {
6798
- import_coc11.window.showWarningMessage("not committed yet!");
6799
- return;
6807
+ return result;
6808
+ }
6809
+ function mergeGutterSigns(unstaged, staged) {
6810
+ const merged = /* @__PURE__ */ new Map();
6811
+ for (const sign of [...staged, ...unstaged]) {
6812
+ const current = merged.get(sign.line);
6813
+ if (!current) {
6814
+ merged.set(sign.line, sign);
6815
+ } else if (current.layer !== sign.layer) {
6816
+ merged.set(sign.line, { line: sign.line, kind: "mixed", layer: "mixed" });
6817
+ } else if (current.layer === "unstaged" || sign.layer === "unstaged") {
6818
+ merged.set(sign.line, sign.layer === "unstaged" ? sign : current);
6819
+ }
6820
+ }
6821
+ return [...merged.values()].sort((a, b) => a.line - b.line);
6822
+ }
6823
+
6824
+ // src/model/buffer.ts
6825
+ var signGroup = "CocGit";
6826
+ var revPattern = "([0-9A-Za-z_.:/-]+)";
6827
+ var startPattern = new RegExp(`^<{7} (${revPattern})(:? .+)?$`);
6828
+ var sepPattern = new RegExp(`^={7}$`);
6829
+ var endPattern = new RegExp(`^>{7} (${revPattern})(:? .+)?$`);
6830
+ var commonPattern = /^\|{7}\smerged\scommon\sancestors/;
6831
+ function getPreviousConflict(conflicts, line) {
6832
+ return conflicts.slice().reverse().find((conflict) => conflict.start < line);
6833
+ }
6834
+ function chunkContainsLine(chunk, line) {
6835
+ const end = chunk.add.count === 0 ? chunk.add.lnum : chunk.add.lnum + chunk.add.count - 1;
6836
+ return chunk.add.lnum <= line && end >= line;
6837
+ }
6838
+ function findCommitLine(lines, relpath, targetLine) {
6839
+ let matchesFile = false;
6840
+ let currentLine;
6841
+ for (let index = 0; index < lines.length; index++) {
6842
+ let text = lines[index];
6843
+ if (text.startsWith("diff --git ")) {
6844
+ matchesFile = parseDiffPath(text) === relpath;
6845
+ currentLine = void 0;
6846
+ continue;
6800
6847
  }
6801
- if (!useFloating) useFloating = this.config.showCommitInFloating;
6802
- if (useFloating) {
6803
- let content = await this.repo.safeRun(["--no-pager", "show", commit]);
6804
- if (content == null) return;
6805
- await this.showDoc(content.trim());
6806
- return;
6848
+ if (!matchesFile) continue;
6849
+ let match = text.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
6850
+ if (match) {
6851
+ currentLine = Number(match[1]);
6852
+ continue;
6807
6853
  }
6808
- await nvim.command(`keepalt above ${this.config.splitWindowCommand}`);
6809
- let hasFugitive = await nvim.getVar("loaded_fugitive");
6810
- if (hasFugitive) {
6811
- await nvim.command(`Gedit ${commit}`);
6812
- } else {
6813
- let content = await this.repo.safeRun(["--no-pager", "show", commit]);
6814
- if (content == null) return;
6815
- let lines = content.trim().split("\n");
6816
- nvim.pauseNotification();
6817
- nvim.command(`edit +setl\\ buftype=nofile [commit ${commit}]`, true);
6818
- nvim.command("setl foldmethod=syntax nobuflisted bufhidden=wipe", true);
6819
- nvim.command("setf git", true);
6820
- nvim.call("append", [0, lines], true);
6821
- nvim.command("normal! Gdd", true);
6822
- nvim.command(`exe 1`, true);
6823
- await nvim.resumeNotification(false, true);
6854
+ if (currentLine == null || !text.startsWith("+") && !text.startsWith(" ")) continue;
6855
+ if (currentLine === targetLine) return index + 1;
6856
+ currentLine++;
6857
+ }
6858
+ return void 0;
6859
+ }
6860
+ var GitBuffer = class {
6861
+ constructor(doc, config, relpath, repo, git, channel, floatFactory, hasConflicts) {
6862
+ this.doc = doc;
6863
+ this.config = config;
6864
+ this.relpath = relpath;
6865
+ this.repo = repo;
6866
+ this.git = git;
6867
+ this.channel = channel;
6868
+ this.floatFactory = floatFactory;
6869
+ this.hasConflicts = hasConflicts;
6870
+ this.blameInfo = [];
6871
+ this.diffs = [];
6872
+ this.conflicts = [];
6873
+ this.currentSigns = [];
6874
+ this.gitState = { staged: [], unstaged: [] };
6875
+ this.gitStatus = "";
6876
+ this.foldEnabled = false;
6877
+ this._disposed = false;
6878
+ this.mutex = new import_coc11.Mutex();
6879
+ this.conflictCheckNeeded = hasConflicts;
6880
+ this.refresh = (0, import_debounce2.default)(() => {
6881
+ this._refresh().catch((e) => {
6882
+ channel.append(`[Error] ${e.message}`);
6883
+ });
6884
+ }, 200);
6885
+ this._refresh().catch((e) => channel.append(`[Error] ${e.message}`));
6886
+ }
6887
+ get cachedDiffs() {
6888
+ return this.diffs;
6889
+ }
6890
+ invalidateStagedCache() {
6891
+ this.stagedCache = void 0;
6892
+ }
6893
+ markConflictCheck() {
6894
+ this.conflictCheckNeeded = true;
6895
+ }
6896
+ async _refresh() {
6897
+ if (this._disposed) return;
6898
+ this.refresh.clear();
6899
+ let release = await this.mutex.acquire();
6900
+ try {
6901
+ if (this._disposed) return;
6902
+ let result = await Promise.all([
6903
+ this.diffDocument(),
6904
+ this.loadBlames(),
6905
+ this.parseConflicts()
6906
+ ].map((promise) => promise.then(() => void 0, (error) => error)));
6907
+ result.forEach((error) => {
6908
+ if (error) this.channel.append(`[Error] refresh error ${error}`);
6909
+ });
6910
+ } finally {
6911
+ release();
6824
6912
  }
6825
6913
  }
6826
- async toggleFold() {
6827
- let { nvim } = import_coc11.workspace;
6914
+ getChunk(line) {
6915
+ if (!this.diffs || this.diffs.length == 0) return void 0;
6916
+ return this.diffs.find((ch) => {
6917
+ let { start, added, removed, changeType } = ch;
6918
+ if (line == 1 && start == 0 && ch.end == 0) {
6919
+ return true;
6920
+ }
6921
+ let end = changeType === "changed" /* Change */ && added.count > removed.count ? ch.end + added.count - removed.count : ch.end;
6922
+ if (start <= line && end >= line) {
6923
+ return true;
6924
+ }
6925
+ return false;
6926
+ });
6927
+ }
6928
+ async chunkUndo() {
6929
+ let line = await import_coc11.workspace.nvim.call("line", ".");
6930
+ let diff = this.getChunk(line);
6931
+ if (!diff) return;
6932
+ let { start, lines, changeType } = diff;
6933
+ let added = lines.filter((s) => s.startsWith("-")).map((s) => s.slice(1));
6934
+ let removeCount = lines.filter((s) => s.startsWith("+")).length;
6828
6935
  let buf = this.doc.buffer;
6829
- let win = await nvim.window;
6830
- let bufnr = buf.id;
6831
- let doc = import_coc11.workspace.getDocument(bufnr);
6832
- if (!doc) return;
6833
- let infos = this.currentSigns;
6834
- if (!infos || infos.length == 0) {
6835
- import_coc11.window.showWarningMessage("No changes");
6936
+ if (changeType == "delete" /* Delete */) {
6937
+ await buf.setLines(added, { start, end: start, strictIndexing: false });
6938
+ } else {
6939
+ await buf.setLines(added, {
6940
+ start: start - 1,
6941
+ end: start - 1 + removeCount,
6942
+ strictIndexing: false
6943
+ });
6944
+ }
6945
+ }
6946
+ async chunkStage() {
6947
+ let relpath = toUnixSlash(this.relpath);
6948
+ let line = await import_coc11.workspace.nvim.call("line", ".");
6949
+ let diff = this.getChunk(line);
6950
+ if (!diff) {
6951
+ import_coc11.window.showErrorMessage("Not positioned in git chunk");
6836
6952
  return;
6837
6953
  }
6838
- let changedLines = new Set(infos.map((o) => o.lnum));
6839
- let foldContext = this.config.foldContext;
6840
- let max = this.doc.lineCount;
6841
- let ranges = [];
6842
- let start = null;
6843
- const addRange = (from, to) => {
6844
- let s = plus(from, foldContext, max);
6845
- let e = minus(to, foldContext, 0);
6846
- if (e - s <= 0) return;
6847
- ranges.push([s, e]);
6848
- };
6849
- for (let i = 1; i <= doc.lineCount; i++) {
6850
- let fold = !changedLines.has(i);
6851
- if (fold && start == null) {
6852
- start = i;
6853
- continue;
6854
- }
6855
- if (start != null && !fold) {
6856
- addRange(start, i - 1);
6857
- start = null;
6954
+ let head;
6955
+ if (diff.changeType === "add" /* Add */) {
6956
+ head = `@@ -${diff.removed.start + 1},0 +${diff.removed.start + 1},${diff.added.count} @@`;
6957
+ } else if (diff.changeType === "delete" /* Delete */) {
6958
+ head = `@@ -${diff.removed.start},${diff.removed.count} +${diff.removed.start},0 @@`;
6959
+ } else if (diff.changeType === "changed" /* Change */) {
6960
+ head = `@@ -${diff.removed.start},${diff.removed.count} +${diff.removed.start},${diff.added.count} @@`;
6961
+ }
6962
+ const from = quoteGitPath(`a/${relpath}`);
6963
+ const to = quoteGitPath(`b/${relpath}`);
6964
+ const lines = [
6965
+ `diff --git ${from} ${to}`,
6966
+ `index 000000..000000 100644`,
6967
+ `--- ${from}`,
6968
+ `+++ ${to}`,
6969
+ head
6970
+ ];
6971
+ lines.push(...diff.lines);
6972
+ lines.push("");
6973
+ try {
6974
+ await this.git.exec(this.repo.root, ["apply", "--cached", "--unidiff-zero", "-"], { input: lines.join("\n") });
6975
+ this.invalidateStagedCache();
6976
+ this.refresh();
6977
+ } catch (e) {
6978
+ this.channel.appendLine(`[Error] ${e.message}`);
6979
+ }
6980
+ }
6981
+ async chunkUnstage() {
6982
+ var _a;
6983
+ let { nvim } = import_coc11.workspace;
6984
+ const { diffs } = this;
6985
+ let line = await nvim.call("line", ".");
6986
+ let adjust = 0;
6987
+ let invalid = false;
6988
+ for (let diff of diffs) {
6989
+ if (diff.end >= line) {
6990
+ if (diff.start <= line && diff.changeType != "delete" /* Delete */) {
6991
+ import_coc11.window.showErrorMessage(`Current line contains unstaged change.`);
6992
+ invalid = true;
6993
+ }
6994
+ break;
6858
6995
  }
6859
- if (start != null && fold && i == doc.lineCount) {
6860
- addRange(start, i);
6996
+ adjust -= diff.added.count;
6997
+ adjust += diff.removed.count;
6998
+ }
6999
+ if (invalid) return;
7000
+ line = line + adjust;
7001
+ let stagedDiff = await this.repo.getStagedChunks(this.relpath);
7002
+ let chunks = (_a = Object.values(stagedDiff)[0]) != null ? _a : [];
7003
+ if (!chunks.length) {
7004
+ import_coc11.window.showErrorMessage(`Staged chunk not found`);
7005
+ return;
7006
+ }
7007
+ let chunk = chunks.find((o) => chunkContainsLine(o, line));
7008
+ if (!chunk) {
7009
+ import_coc11.window.showErrorMessage(`Unable to find staged chunk on current line`);
7010
+ return;
7011
+ }
7012
+ this.channel.appendLine(`[Info] resolved chunk ${JSON.stringify(chunk, null, 2)}`);
7013
+ let patch = createUnstagePatch(this.relpath, chunk);
7014
+ if (!patch) return;
7015
+ try {
7016
+ await this.git.exec(this.repo.root, ["apply", "--cached", "--unidiff-zero", "-"], { input: patch });
7017
+ this.invalidateStagedCache();
7018
+ this.refresh();
7019
+ } catch (e) {
7020
+ import_coc11.window.showErrorMessage(`Unable to apply patch: ${e.message}`);
7021
+ this.channel.appendLine(`[Error] ${e.message}`);
7022
+ }
7023
+ }
7024
+ async nextChunk() {
7025
+ if (this.config.enableStagedGutters) {
7026
+ await this.moveToNextChunk();
7027
+ return;
7028
+ }
7029
+ const { diffs } = this;
7030
+ let { nvim } = import_coc11.workspace;
7031
+ if (!diffs || diffs.length == 0) return;
7032
+ let line = await nvim.call("line", ".");
7033
+ for (let diff of diffs) {
7034
+ if (diff.start > line) {
7035
+ await import_coc11.window.moveTo({ line: Math.max(diff.start - 1, 0), character: 0 });
7036
+ return;
6861
7037
  }
6862
7038
  }
6863
- let enabled = this.foldEnabled;
6864
- if (enabled) {
6865
- this.foldEnabled = false;
6866
- let cursor = await nvim.eval('getpos(".")');
6867
- let lnums = ranges.map((o) => o[0]);
6868
- let settings = this.foldSettings;
6869
- nvim.pauseNotification();
6870
- for (let lnum of lnums) {
6871
- nvim.command(`${lnum}normal! zd`, true);
7039
+ if (await nvim.getOption("wrapscan")) {
7040
+ await import_coc11.window.moveTo({ line: Math.max(diffs[0].start - 1, 0), character: 0 });
7041
+ }
7042
+ }
7043
+ async prevChunk() {
7044
+ if (this.config.enableStagedGutters) {
7045
+ await this.moveToPreviousChunk();
7046
+ return;
7047
+ }
7048
+ const { nvim } = import_coc11.workspace;
7049
+ let { diffs } = this;
7050
+ let line = await nvim.call("line", ".");
7051
+ if (!diffs || diffs.length == 0) return;
7052
+ for (let diff of diffs.slice().reverse()) {
7053
+ if (diff.end < line) {
7054
+ await import_coc11.window.moveTo({ line: Math.max(diff.start - 1, 0), character: 0 });
7055
+ return;
6872
7056
  }
6873
- win.setOption("foldmethod", settings.foldmethod, true);
6874
- win.setOption("foldenable", settings.foldenable, true);
6875
- win.setOption("foldlevel", settings.foldlevel, true);
6876
- nvim.call("setpos", [".", cursor], true);
6877
- await nvim.resumeNotification();
6878
- } else {
6879
- this.foldEnabled = true;
6880
- let [foldmethod, foldenable, foldlevel] = await nvim.eval("[&foldmethod,&foldenable,&foldlevel]");
6881
- this.foldSettings = {
6882
- foldmethod,
6883
- foldenable: foldenable !== 0,
6884
- foldlevel
6885
- };
6886
- nvim.pauseNotification();
6887
- win.setOption("foldmethod", "manual", true);
6888
- nvim.command("silent! normal! zE", true);
6889
- win.setOption("foldenable", true, true);
6890
- win.setOption("foldlevel", 0, true);
6891
- await nvim.resumeNotification();
6892
- nvim.pauseNotification();
6893
- for (let r of ranges) {
6894
- nvim.command(`${r[0]},${r[1]}fold`, true);
7057
+ }
7058
+ if (await nvim.getOption("wrapscan")) {
7059
+ await import_coc11.window.moveTo({ line: Math.max(diffs[diffs.length - 1].start - 1, 0), character: 0 });
7060
+ }
7061
+ }
7062
+ getNavigationChunks() {
7063
+ const chunks = [
7064
+ ...this.diffs.map((diff) => ({
7065
+ start: Math.max(1, diff.start),
7066
+ end: Math.max(1, diff.end)
7067
+ })),
7068
+ ...this.gitState.staged.map((change) => {
7069
+ var _a;
7070
+ return {
7071
+ start: Math.max(1, change.line),
7072
+ end: Math.max(1, (_a = change.endLine) != null ? _a : change.line)
7073
+ };
7074
+ })
7075
+ ].sort((a, b) => a.start - b.start || a.end - b.end);
7076
+ const result = [];
7077
+ for (const chunk of chunks) {
7078
+ const previous = result[result.length - 1];
7079
+ if (previous && chunk.start <= previous.end) {
7080
+ previous.end = Math.max(previous.end, chunk.end);
7081
+ } else {
7082
+ result.push({ ...chunk });
6895
7083
  }
6896
- await nvim.resumeNotification();
6897
7084
  }
7085
+ return result;
6898
7086
  }
6899
- async toggleGutters(enabled) {
6900
- this.config.enableGutters = enabled;
6901
- let { nvim } = import_coc11.workspace;
6902
- if (!enabled) {
6903
- nvim.call("sign_unplace", [signGroup, { buffer: this.doc.bufnr }], true);
6904
- nvim.redrawVim();
6905
- } else {
6906
- this.diffs = [];
6907
- await this.diffDocument(true);
7087
+ async moveToNextChunk() {
7088
+ const chunks = this.getNavigationChunks();
7089
+ const { nvim } = import_coc11.workspace;
7090
+ if (chunks.length === 0) return;
7091
+ const line = await nvim.call("line", ".");
7092
+ for (const chunk of chunks) {
7093
+ if (chunk.start > line) {
7094
+ await import_coc11.window.moveTo({ line: Math.max(chunk.start - 1, 0), character: 0 });
7095
+ return;
7096
+ }
7097
+ }
7098
+ if (await nvim.getOption("wrapscan")) {
7099
+ await import_coc11.window.moveTo({ line: Math.max(chunks[0].start - 1, 0), character: 0 });
6908
7100
  }
6909
7101
  }
6910
- async parseConflicts() {
6911
- if (!this.config.conflict.enabled) {
6912
- if (this.conflicts.length) {
6913
- this.conflicts = [];
6914
- await this.highlightConflicts([]);
7102
+ async moveToPreviousChunk() {
7103
+ const chunks = this.getNavigationChunks();
7104
+ const { nvim } = import_coc11.workspace;
7105
+ if (chunks.length === 0) return;
7106
+ const line = await nvim.call("line", ".");
7107
+ for (const chunk of chunks.slice().reverse()) {
7108
+ if (chunk.end < line) {
7109
+ await import_coc11.window.moveTo({ line: Math.max(chunk.start - 1, 0), character: 0 });
7110
+ return;
6915
7111
  }
6916
- return;
6917
7112
  }
6918
- if (!this.hasConflicts && !this.conflictCheckNeeded) return;
6919
- this.conflictCheckNeeded = false;
6920
- this.hasConflicts = await this.repo.hasConflicts(this.relpath);
6921
- if (this._disposed) return;
6922
- if (!this.hasConflicts) {
6923
- this.conflicts = [];
6924
- await this.highlightConflicts([]);
6925
- return;
7113
+ if (await nvim.getOption("wrapscan")) {
7114
+ await import_coc11.window.moveTo({ line: Math.max(chunks[chunks.length - 1].start - 1, 0), character: 0 });
6926
7115
  }
6927
- const lines = this.doc.textDocument.lines;
6928
- let conflicts = [];
6929
- let conflict = null;
6930
- let state = 0 /* Initial */;
6931
- let mkStartConflict = (index, current) => ({
6932
- start: index + 1,
6933
- sep: 0,
6934
- end: 0,
6935
- current,
6936
- incoming: ""
6937
- });
6938
- lines.forEach((line, index) => {
6939
- switch (state) {
6940
- case 0 /* Initial */: {
6941
- const match = line.match(startPattern);
6942
- if (match) {
6943
- conflict = mkStartConflict(index, match[1]);
6944
- state = 1 /* MatchedStart */;
6945
- }
6946
- break;
6947
- }
6948
- case 2 /* MatchedCommon */:
6949
- case 1 /* MatchedStart */: {
6950
- let match = line.match(sepPattern);
6951
- if (match) {
6952
- conflict.sep = index + 1;
6953
- state = 3 /* MatchedSep */;
6954
- } else {
6955
- const startMatch = line.match(startPattern);
6956
- if (startMatch) {
6957
- conflict = mkStartConflict(index, startMatch[1]);
6958
- state = 1 /* MatchedStart */;
6959
- } else if (line.match(endPattern)) {
6960
- conflict = null;
6961
- state = 0 /* Initial */;
6962
- } else if (line.match(commonPattern)) {
6963
- conflict.common = index + 1;
6964
- state = 2 /* MatchedCommon */;
6965
- }
6966
- }
6967
- break;
6968
- }
6969
- case 3 /* MatchedSep */: {
6970
- const match = line.match(endPattern);
6971
- if (match) {
6972
- conflict.end = index + 1;
6973
- conflict.incoming = match[1];
6974
- conflicts.push(conflict);
6975
- conflict = null;
6976
- state = 0 /* Initial */;
6977
- } else {
6978
- const startMatch = line.match(startPattern);
6979
- if (startMatch) {
6980
- conflict = mkStartConflict(index, startMatch[1]);
6981
- state = 1 /* MatchedStart */;
6982
- } else if (line.match(sepPattern)) {
6983
- conflict = null;
6984
- state = 0 /* Initial */;
6985
- }
6986
- }
7116
+ }
7117
+ async chunkInfo() {
7118
+ let line = await import_coc11.workspace.nvim.call("line", ".");
7119
+ let diff = this.getChunk(line);
7120
+ if (diff) {
7121
+ let content = diff.head + "\n" + diff.lines.join("\n");
7122
+ await this.showDoc(content, "diff");
7123
+ } else {
7124
+ let chunks = [];
7125
+ try {
7126
+ let stagedDiff = await this.repo.getStagedChunks(this.relpath);
7127
+ chunks = Object.values(stagedDiff)[0];
7128
+ } catch (e) {
7129
+ }
7130
+ let adjust = 0;
7131
+ for (let diff2 of this.diffs) {
7132
+ if (diff2.end >= line) {
6987
7133
  break;
6988
7134
  }
7135
+ adjust -= diff2.added.count;
7136
+ adjust += diff2.removed.count;
7137
+ }
7138
+ line = line + adjust;
7139
+ let chunk = chunks.find((o) => chunkContainsLine(o, line));
7140
+ if (chunk) {
7141
+ let content = "Staged changes\n" + chunk.lines.join("\n");
7142
+ await this.showDoc(content, "diff");
7143
+ } else {
7144
+ await this.showCommit(true);
6989
7145
  }
6990
- });
6991
- this.conflicts = conflicts;
6992
- await this.highlightConflicts(conflicts);
6993
- if (conflicts.length == 0) {
6994
- this.hasConflicts = false;
6995
7146
  }
6996
7147
  }
6997
- async highlightConflicts(conflicts) {
7148
+ allChunkInfo() {
7149
+ return this.diffs ? this.diffs.slice() : [];
7150
+ }
7151
+ async showBlameInfo(lnum) {
6998
7152
  if (this._disposed) return;
6999
- let buffer = this.doc.buffer;
7000
- let currentHlGroup = this.config.conflict.currentHlGroup;
7001
- let incomingHlGroup = this.config.conflict.incomingHlGroup;
7002
- let commonHlGroup = this.config.conflict.commonHlGroup;
7003
7153
  let { nvim } = import_coc11.workspace;
7004
- nvim.pauseNotification();
7005
- buffer.clearNamespace(this.config.conflictSrcId, 0, -1);
7006
- const srcId = this.config.conflictSrcId;
7007
- conflicts.map((conflict) => {
7008
- let currEnd = conflict.common ? conflict.common - 1 : conflict.sep - 1;
7009
- let currRange = import_coc11.Range.create(import_coc11.Position.create(conflict.start - 1, 0), import_coc11.Position.create(currEnd, 0));
7010
- let incomingRange = import_coc11.Range.create(import_coc11.Position.create(conflict.sep, 0), import_coc11.Position.create(conflict.end, 0));
7011
- buffer.highlightRanges(srcId, currentHlGroup, [currRange]);
7012
- buffer.highlightRanges(srcId, incomingHlGroup, [incomingRange]);
7013
- if (conflict.common) {
7014
- let range = import_coc11.Range.create(import_coc11.Position.create(conflict.common - 1, 0), import_coc11.Position.create(conflict.sep - 1, 0));
7015
- buffer.highlightRanges(srcId, commonHlGroup, [range]);
7154
+ let { virtualTextSrcId, addGBlameToBufferVar, addGBlameToVirtualText } = this.config;
7155
+ if (!this.showBlame) return;
7156
+ let infos = this.blameInfo;
7157
+ if (!infos) return;
7158
+ let blameText;
7159
+ if (infos.length == 0) {
7160
+ blameText = "File not indexed";
7161
+ } else {
7162
+ let info = infos.find((o) => lnum >= o.startLnum && lnum <= o.endLnum);
7163
+ if (info && info.author && info.author != "Not Committed Yet") {
7164
+ blameText = formatBlameText(info, this.config.blameFormat);
7165
+ } else {
7166
+ blameText = "Not committed yet";
7016
7167
  }
7017
- });
7018
- nvim.resumeNotification(false, true);
7168
+ }
7169
+ let buffer = nvim.createBuffer(this.doc.bufnr);
7170
+ let hide_blame = await nvim.getVar("coc_git_hide_blame_virtual_text");
7171
+ if (hide_blame) {
7172
+ buffer.clearNamespace(virtualTextSrcId);
7173
+ } else {
7174
+ if (addGBlameToBufferVar) {
7175
+ nvim.pauseNotification();
7176
+ buffer.setVar("coc_git_blame", blameText, true);
7177
+ nvim.call("coc#util#do_autocmd", ["CocGitStatusChange"], true);
7178
+ nvim.resumeNotification(false, true);
7179
+ }
7180
+ if (addGBlameToVirtualText) {
7181
+ const prefix = this.config.virtualTextPrefix;
7182
+ nvim.pauseNotification();
7183
+ buffer.clearNamespace(virtualTextSrcId);
7184
+ buffer.setVirtualText(virtualTextSrcId, lnum - 1, [[prefix + blameText, "CocCodeLens"]]);
7185
+ nvim.resumeNotification(true, true);
7186
+ }
7187
+ }
7019
7188
  }
7020
- async showDoc(content, filetype = "diff") {
7021
- if (this.floatFactory) {
7022
- let docs = [{ content, filetype }];
7023
- await this.floatFactory.show(docs, this.config.floatConfig);
7189
+ async showBlameDoc(lnum) {
7190
+ let indexed = await this.repo.isIndexed(this.relpath);
7191
+ if (!indexed) {
7192
+ import_coc11.window.showWarningMessage("File not indexed");
7193
+ } else if (await this.repo.isShallow()) {
7194
+ import_coc11.window.showWarningMessage("Shallow repository, blame not available");
7024
7195
  } else {
7025
- const lines = content.split("\n");
7026
- import_coc11.workspace.nvim.call("coc#ui#preview_info", [lines, filetype], true);
7196
+ let infos = await this.getBlameInfo([lnum, lnum]);
7197
+ let info = infos.find((o) => lnum >= o.startLnum && lnum <= o.endLnum);
7198
+ if (info && info.author && info.author != "Not Committed Yet") {
7199
+ let blameText = [];
7200
+ blameText.push(`${info.author}, ${info.time}`);
7201
+ blameText.push(`${info.summary}`);
7202
+ blameText.push(`${info.sha.substring(0, 7)}`);
7203
+ await this.showDoc(blameText.join("\n\n"), "text");
7204
+ } else {
7205
+ import_coc11.window.showWarningMessage("Not committed yet");
7206
+ }
7027
7207
  }
7028
7208
  }
7029
- setBufferStatus(status) {
7030
- let exists = this.gitStatus;
7031
- if (exists == status) return;
7032
- this.gitStatus = status;
7209
+ async diffDocument(force = false) {
7033
7210
  let { nvim } = import_coc11.workspace;
7034
- let buffer = nvim.createBuffer(this.doc.bufnr);
7035
- nvim.pauseNotification();
7036
- buffer.setVar("coc_git_status", status, true);
7037
- nvim.callTimer("coc#util#do_autocmd", ["CocGitStatusChange"], true);
7038
- nvim.resumeNotification(false, true);
7039
- }
7040
- getSignName(changeType) {
7041
- switch (changeType) {
7042
- case "delete" /* Delete */:
7043
- return "CocGitRemoved";
7044
- case "add" /* Add */:
7045
- return "CocGitAdded";
7046
- case "changed" /* Change */:
7047
- return "CocGitChanged";
7048
- case "topdelete":
7049
- return "CocGitTopRemoved";
7050
- case "changedelete":
7051
- return "CocGitChangeRemoved";
7211
+ let revision = this.config.diffRevision;
7212
+ const { bufnr } = this.doc;
7213
+ let content = this.doc.content;
7214
+ let eol = this.doc.textDocument["eol"];
7215
+ let encoding = await this.doc.buffer.getOption("fileencoding");
7216
+ const diffs = await this.repo.getDiff(this.relpath, eol ? content : content + "\n", revision, encoding || "utf8");
7217
+ if (diffs == null || this._disposed) return;
7218
+ const unstaged = changesFromDiffs(diffs, "unstaged");
7219
+ let staged = [];
7220
+ let stagedLines = [];
7221
+ if (this.config.enableStagedGutters) {
7222
+ const cached = await this.getStagedChanges(encoding || "utf8");
7223
+ if (cached) {
7224
+ staged = cached.changes;
7225
+ stagedLines = cached.indexLines;
7226
+ }
7052
7227
  }
7053
- return "";
7228
+ if (this._disposed) return;
7229
+ const oldState = this.gitState;
7230
+ const mapping = createLineMapping(stagedLines, this.doc.textDocument.lines, unstaged);
7231
+ const mappedStaged = staged.length ? mapIndexChangesToBuffer(staged, mapping, this.doc.textDocument.lines.length) : [];
7232
+ const unstagedSigns = gutterSignsFromChanges(unstaged);
7233
+ const stagedSigns = gutterSignsFromChanges(mappedStaged);
7234
+ const currentSigns = mergeGutterSigns(unstagedSigns, this.config.enableStagedGutters ? stagedSigns : []);
7235
+ this.diffs = diffs;
7236
+ this.gitState = { staged: mappedStaged, unstaged };
7237
+ if (equals(oldState, this.gitState) && !force) return;
7238
+ let added = 0;
7239
+ let changed = 0;
7240
+ let removed = 0;
7241
+ for (let diff of diffs) {
7242
+ if (diff.changeType == "add" /* Add */) {
7243
+ added += diff.added.count;
7244
+ } else if (diff.changeType == "delete" /* Delete */) {
7245
+ removed += diff.removed.count;
7246
+ } else if (diff.changeType == "changed" /* Change */) {
7247
+ let [add, remove] = [diff.added.count, diff.removed.count];
7248
+ let min = Math.min(add, remove);
7249
+ changed += min;
7250
+ added += add - min;
7251
+ removed += remove - min;
7252
+ }
7253
+ }
7254
+ let items = [];
7255
+ if (added) items.push(`+${added}`);
7256
+ if (changed) items.push(`~${changed}`);
7257
+ if (removed) items.push(`-${removed}`);
7258
+ let status = ` ${items.join(" ")} `;
7259
+ this.setBufferStatus(status);
7260
+ this.currentSigns = currentSigns;
7261
+ if (this.currentSigns.length === 0) {
7262
+ if (this.config.enableGutters) {
7263
+ nvim.call("sign_unplace", [signGroup, { buffer: bufnr }], true);
7264
+ nvim.redrawVim();
7265
+ }
7266
+ return;
7267
+ }
7268
+ if (!this.config.realtimeGutters && !force) return;
7269
+ this.updateGutters();
7054
7270
  }
7055
- get showBlame() {
7056
- return this.config.addGBlameToVirtualText || this.config.addGBlameToBufferVar;
7271
+ async getStagedChanges(encoding) {
7272
+ const [indexIdentity, headIdentity] = await Promise.all([
7273
+ this.repo.getIndexIdentity(),
7274
+ this.repo.getHeadIdentity()
7275
+ ]);
7276
+ if (this.stagedCache && this.stagedCache.indexIdentity === indexIdentity && this.stagedCache.headIdentity === headIdentity) {
7277
+ return { changes: this.stagedCache.stagedInIndex, indexLines: this.stagedCache.indexLines };
7278
+ }
7279
+ const [head, index] = await Promise.all([
7280
+ this.repo.getFileContent(this.relpath, "HEAD:", encoding),
7281
+ this.repo.getFileContent(this.relpath, ":", encoding)
7282
+ ]);
7283
+ const stagedDiffs = await this.repo.getDiffFromContents(head ? head + "\n" : "", index ? index + "\n" : "");
7284
+ const stagedInIndex = changesFromDiffs(stagedDiffs, "staged");
7285
+ const headLines = head ? head.split("\n") : [];
7286
+ const indexLines = index ? index.split("\n") : [];
7287
+ this.stagedCache = { indexIdentity, headIdentity, headLines, indexLines, stagedInIndex };
7288
+ return { changes: stagedInIndex, indexLines };
7057
7289
  }
7058
- dispose() {
7290
+ updateGutters() {
7059
7291
  if (this._disposed) return;
7060
- this._disposed = true;
7292
+ if (!this.config.enableGutters) return;
7061
7293
  let { nvim } = import_coc11.workspace;
7062
7294
  let { bufnr } = this.doc;
7063
- let buffer = nvim.createBuffer(bufnr);
7295
+ let { signPriority, stagedSignPriority } = this.config;
7296
+ let signs = this.currentSigns;
7064
7297
  nvim.pauseNotification();
7065
- buffer.setVar("coc_git_status", "", true);
7066
- buffer.clearNamespace(this.config.conflictSrcId, 0, -1);
7067
7298
  nvim.call("sign_unplace", [signGroup, { buffer: bufnr }], true);
7068
- this.refresh.clear();
7069
- if (this.config.addGBlameToBufferVar) {
7070
- buffer.setVar("coc_git_blame", "", true);
7071
- }
7072
- if (this.config.addGBlameToVirtualText) {
7073
- buffer.clearNamespace(this.config.virtualTextSrcId);
7299
+ for (let sign of signs) {
7300
+ let name = this.getSignName(sign.kind, sign.layer);
7301
+ const priority = sign.layer === "staged" ? stagedSignPriority : signPriority;
7302
+ nvim.call("sign_place", [0, signGroup, name, bufnr, { lnum: sign.line, priority }], true);
7074
7303
  }
7075
- nvim.resumeNotification(false, true);
7076
- this.foldEnabled = false;
7077
- }
7078
- };
7079
- function plus(val, count, max) {
7080
- if (!count) return val;
7081
- val = val + count;
7082
- return Math.min(max, val);
7083
- }
7084
- function minus(val, count, min) {
7085
- if (!count) return val;
7086
- val = val - count;
7087
- return Math.max(min, val);
7088
- }
7089
-
7090
- // src/model/git.ts
7091
- var cp = __toESM(require("child_process"));
7092
- var import_coc12 = require("coc.nvim");
7093
- var import_iconv_lite = __toESM(require_lib());
7094
- var import_path5 = __toESM(require("path"));
7095
- var Git = class {
7096
- constructor(gitInfo, channel) {
7097
- this.gitInfo = gitInfo;
7098
- this.channel = channel;
7304
+ nvim.resumeNotification(true, true);
7099
7305
  }
7100
- get path() {
7101
- return this.gitInfo.path;
7306
+ async loadBlames() {
7307
+ if (!this.showBlame) return;
7308
+ let result = [];
7309
+ let indexed = await this.repo.isIndexed(this.relpath);
7310
+ if (indexed) result = await this.getBlameInfo();
7311
+ if (this._disposed) return;
7312
+ this.blameInfo = result;
7102
7313
  }
7103
- async getRepositoryRoot(repositoryPath) {
7104
- const result = await this.exec(repositoryPath, ["rev-parse", "--show-toplevel"]);
7105
- let repoRootPath = import_path5.default.normalize(result.stdout.trim());
7106
- if (process.platform === "win32" && repoRootPath.startsWith("\\") && !process.env.SHELL) {
7107
- repoRootPath = repoRootPath.replace(/^\\([^\\]*)\\/, "$1:\\");
7314
+ async getBlameInfo(range) {
7315
+ let { relpath } = this;
7316
+ let root = this.repo.root;
7317
+ let res = [];
7318
+ const useRealTime = this.config.blameUseRealTime;
7319
+ try {
7320
+ let currentAuthor = await this.repo.getUsername();
7321
+ const args = ["--no-pager", "blame", "-w", "-b", "-p", "--incremental", "--root", "--date", "relative", "--contents", "-"];
7322
+ if (range) args.push("-L", range.join(","));
7323
+ args.push("--", relpath);
7324
+ let r = await this.git.exec(root, args, {
7325
+ log: false,
7326
+ input: this.doc.content
7327
+ });
7328
+ if (!r.stdout) return res;
7329
+ let info;
7330
+ const commits = /* @__PURE__ */ new Map();
7331
+ for (let line of r.stdout.trim().split(/\r?\n/)) {
7332
+ line = line.trim();
7333
+ if (/^(author |committer )?External file \(--contents\)/.test(line)) {
7334
+ line = "Not committed yet.";
7335
+ }
7336
+ let ms = line.match(/^([A-Za-z0-9]+)\s(\d+)\s(\d+)\s(\d+)/);
7337
+ if (ms) {
7338
+ let startLnum = parseInt(ms[3], 10);
7339
+ info = { startLnum, sha: ms[1], endLnum: startLnum + parseInt(ms[4], 10) - 1, index: ms[2] };
7340
+ if (!/^0+$/.test(ms[1])) {
7341
+ let find = commits.get(ms[1]);
7342
+ if (find) {
7343
+ info.author = find.author;
7344
+ info.time = find.time;
7345
+ info.summary = find.summary;
7346
+ } else {
7347
+ commits.set(ms[1], info);
7348
+ }
7349
+ }
7350
+ res.push(info);
7351
+ } else if (info) {
7352
+ if (line.startsWith("author ")) {
7353
+ let author = line.replace(/^author/, "").trim();
7354
+ info.author = author == currentAuthor ? "You" : author;
7355
+ } else if (line.startsWith("author-time ")) {
7356
+ let text = line.replace(/^author-time/, "").trim();
7357
+ const timestamps = parseInt(text, 10) * 1e3;
7358
+ info.time = useRealTime ? new Date(timestamps).toLocaleString() : format(timestamps, process.env.LANG);
7359
+ } else if (line.startsWith("summary ")) {
7360
+ let text = line.replace(/^summary/, "").trim();
7361
+ info.summary = text;
7362
+ }
7363
+ }
7364
+ }
7365
+ return res;
7366
+ } catch (e) {
7367
+ this.channel.appendLine(e.stack);
7108
7368
  }
7109
- return repoRootPath;
7110
- }
7111
- async exec(cwd, args, options = {}) {
7112
- options = Object.assign({ cwd }, options || {});
7113
- return await this._exec(args, options);
7114
- }
7115
- stream(cwd, args, options = {}) {
7116
- options = Object.assign({ cwd }, options || {});
7117
- return this.spawn(args, options);
7369
+ return res;
7118
7370
  }
7119
- async _exec(args, options = {}) {
7120
- var _a, _b, _c, _d;
7121
- if ((_a = options.cancellationToken) == null ? void 0 : _a.isCancellationRequested) {
7122
- throw new Error("Cancelled");
7371
+ async diffCached() {
7372
+ let res = await this.repo.safeRun(["diff", "--cached"]);
7373
+ if (!res.trim()) {
7374
+ import_coc11.window.showWarningMessage("Empty diff");
7375
+ return;
7123
7376
  }
7124
- const child = this.spawn(args, options);
7125
- if (options.input !== void 0) {
7126
- (_b = child.stdin) == null ? void 0 : _b.on("error", () => {
7127
- });
7128
- (_c = child.stdin) == null ? void 0 : _c.end(options.input, "utf8");
7377
+ let { nvim } = import_coc11.workspace;
7378
+ nvim.pauseNotification();
7379
+ nvim.command(`keepalt above new +setl\\ previewwindow`, true);
7380
+ nvim.call("append", [0, res.split(/\r?\n/)], true);
7381
+ nvim.command("normal! Gdd", true);
7382
+ nvim.command(`exe 1`, true);
7383
+ nvim.command("setfiletype git", true);
7384
+ nvim.command("setl buftype=nofile nomodifiable bufhidden=wipe nobuflisted", true);
7385
+ await nvim.resumeNotification();
7386
+ }
7387
+ async nextConflict() {
7388
+ let { nvim } = import_coc11.workspace;
7389
+ if (!this.conflicts.length) {
7390
+ import_coc11.window.showWarningMessage("No conflicts detected");
7391
+ return;
7129
7392
  }
7130
- const bufferResult = await exec2(child, options.cancellationToken);
7131
- if (options.log !== false && bufferResult.stderr.length > 0) {
7132
- this.log(`${bufferResult.stderr}
7133
- `);
7393
+ let line = await nvim.call("line", ".");
7394
+ for (let conflict of this.conflicts) {
7395
+ if (conflict.start > line) {
7396
+ await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
7397
+ return;
7398
+ }
7134
7399
  }
7135
- let encoding = options.encoding || "utf8";
7136
- encoding = import_iconv_lite.default.encodingExists(encoding) ? encoding : "utf8";
7137
- const result = {
7138
- exitCode: bufferResult.exitCode,
7139
- stdout: import_iconv_lite.default.decode(bufferResult.stdout, encoding),
7140
- stderr: bufferResult.stderr
7141
- };
7142
- if (bufferResult.exitCode && !((_d = options.allowedExitCodes) == null ? void 0 : _d.includes(bufferResult.exitCode))) {
7143
- this.channel.appendLine(`Error ${result.exitCode} on: 'git ${args.join(" ")}' in ${options.cwd}`);
7144
- this.channel.append(result.stderr);
7145
- this.channel.append(result.stdout);
7146
- return Promise.reject(new Error("Failed to execute git"));
7400
+ if (await nvim.getOption("wrapscan")) {
7401
+ await import_coc11.window.moveTo({ line: Math.max(this.conflicts[0].start - 1, 0), character: 0 });
7147
7402
  }
7148
- return result;
7149
7403
  }
7150
- spawn(args, options = {}) {
7151
- const { input, encoding: _encoding, log: _log, cancellationToken: _cancellationToken, allowedExitCodes: _allowedExitCodes, ...spawnOptions } = options;
7152
- if (!spawnOptions.stdio && input === void 0) {
7153
- spawnOptions.stdio = ["ignore", null, null];
7404
+ async prevConflict() {
7405
+ let { nvim } = import_coc11.workspace;
7406
+ if (!this.conflicts.length) {
7407
+ import_coc11.window.showWarningMessage("No conflicts detected", "warning");
7408
+ return;
7154
7409
  }
7155
- spawnOptions.env = Object.assign({}, process.env, spawnOptions.env || {}, {
7156
- LC_ALL: "en_US.UTF-8",
7157
- LANG: "en_US.UTF-8"
7158
- });
7159
- if (options.log !== false) {
7160
- this.log(`> git ${args.join(" ")}
7161
- `);
7410
+ let line = await nvim.call("line", ".");
7411
+ let conflict = getPreviousConflict(this.conflicts, line);
7412
+ if (conflict) {
7413
+ await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
7414
+ return;
7415
+ }
7416
+ if (await nvim.getOption("wrapscan")) {
7417
+ conflict = this.conflicts[this.conflicts.length - 1];
7418
+ await import_coc11.window.moveTo({ line: Math.max(conflict.start - 1, 0), character: 0 });
7162
7419
  }
7163
- return cp.spawn(this.gitInfo.path, args, spawnOptions);
7164
- }
7165
- log(output) {
7166
- this.channel.append(output);
7167
- }
7168
- };
7169
- var git_default = Git;
7170
- async function exec2(child, cancellationToken) {
7171
- if (!child.stdout || !child.stderr) {
7172
- throw new Error("Failed to get stdout or stderr from git process.");
7173
- }
7174
- if (cancellationToken && cancellationToken.isCancellationRequested) {
7175
- throw new Error("Cancelled");
7176
7420
  }
7177
- const disposables = [];
7178
- const once = (ee, name, fn) => {
7179
- ee.once(name, fn);
7180
- disposables.push(import_coc12.Disposable.create(() => ee.removeListener(name, fn)));
7181
- };
7182
- const on = (ee, name, fn) => {
7183
- ee.on(name, fn);
7184
- disposables.push(import_coc12.Disposable.create(() => ee.removeListener(name, fn)));
7185
- };
7186
- let result = Promise.all([
7187
- new Promise((c, e) => {
7188
- once(child, "error", cpErrorHandler(e));
7189
- once(child, "exit", (code) => c(code != null ? code : -1));
7190
- }),
7191
- new Promise((c) => {
7192
- const buffers = [];
7193
- on(child.stdout, "data", (b) => buffers.push(b));
7194
- once(child.stdout, "close", () => c(Buffer.concat(buffers)));
7195
- }),
7196
- new Promise((c) => {
7197
- const buffers = [];
7198
- on(child.stderr, "data", (b) => buffers.push(b));
7199
- once(child.stderr, "close", () => c(Buffer.concat(buffers).toString("utf8")));
7200
- })
7201
- ]);
7202
- if (cancellationToken) {
7203
- const cancellationPromise = new Promise((_, e) => {
7204
- const disposable = onceEvent(cancellationToken.onCancellationRequested)(() => {
7205
- try {
7206
- child.kill();
7207
- } catch (err) {
7421
+ async conflictKeepPart(part) {
7422
+ const { nvim } = import_coc11.workspace;
7423
+ let conflicts = this.conflicts;
7424
+ if (!conflicts || conflicts.length == 0) {
7425
+ import_coc11.window.showWarningMessage("No conflicts detected");
7426
+ return;
7427
+ }
7428
+ let line = await nvim.call("line", ".");
7429
+ for (let conflict of conflicts) {
7430
+ if (conflict.start <= line && conflict.end >= line) {
7431
+ switch (part) {
7432
+ case 0 /* Current */:
7433
+ let start = conflict.common ? conflict.common : conflict.sep;
7434
+ await nvim.command(`${start},${conflict.end}d | ${conflict.start}d`);
7435
+ return;
7436
+ case 1 /* Incoming */:
7437
+ await nvim.command(`${conflict.end}d | ${conflict.start},${conflict.sep}d`);
7438
+ return;
7439
+ case 2 /* Both */:
7440
+ if (conflict.common) {
7441
+ await nvim.command(`${conflict.end}d | ${conflict.common},${conflict.sep}d | ${conflict.start}d`);
7442
+ } else {
7443
+ await nvim.command(`${conflict.end}d | ${conflict.sep}d | ${conflict.start}d`);
7444
+ }
7445
+ return;
7208
7446
  }
7209
- e(new Error("Cancelled"));
7210
- });
7211
- disposables.push(disposable);
7212
- });
7213
- result = Promise.race([result, cancellationPromise]);
7214
- }
7215
- try {
7216
- const [exitCode, stdout, stderr] = await result;
7217
- return { exitCode, stdout, stderr };
7218
- } finally {
7219
- (0, import_coc12.disposeAll)(disposables);
7220
- }
7221
- }
7222
-
7223
- // src/model/repo.ts
7224
- var import_fs2 = __toESM(require("fs"));
7225
- var import_os = __toESM(require("os"));
7226
- var import_path6 = __toESM(require("path"));
7227
- var import_util5 = __toESM(require("util"));
7228
-
7229
- // node_modules/uuid/dist/esm/stringify.js
7230
- var byteToHex = [];
7231
- for (let i = 0; i < 256; ++i) {
7232
- byteToHex.push((i + 256).toString(16).slice(1));
7233
- }
7234
- function unsafeStringify(arr, offset = 0) {
7235
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
7236
- }
7237
-
7238
- // node_modules/uuid/dist/esm/rng.js
7239
- var import_crypto = require("crypto");
7240
- var rnds8Pool = new Uint8Array(256);
7241
- var poolPtr = rnds8Pool.length;
7242
- function rng() {
7243
- if (poolPtr > rnds8Pool.length - 16) {
7244
- (0, import_crypto.randomFillSync)(rnds8Pool);
7245
- poolPtr = 0;
7447
+ }
7448
+ }
7449
+ import_coc11.window.showWarningMessage("Not positioned on a conflict");
7246
7450
  }
7247
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
7248
- }
7249
-
7250
- // node_modules/uuid/dist/esm/native.js
7251
- var import_crypto2 = require("crypto");
7252
- var native_default = { randomUUID: import_crypto2.randomUUID };
7253
-
7254
- // node_modules/uuid/dist/esm/v4.js
7255
- function v4(options, buf, offset) {
7256
- var _a, _b, _c;
7257
- if (native_default.randomUUID && !buf && !options) {
7258
- return native_default.randomUUID();
7451
+ async browser(action = "open", range, permalink = false) {
7452
+ let { nvim } = import_coc11.workspace;
7453
+ let config = import_coc11.workspace.getConfiguration("git");
7454
+ let head = (await this.repo.safeRun(["rev-parse", "HEAD"])).trim();
7455
+ let branch = config.get("browserBranchName", "").trim();
7456
+ if (!branch.length) {
7457
+ branch = (await this.repo.safeRun(["symbolic-ref", "--short", "-q", "HEAD"])).trim();
7458
+ }
7459
+ let lines = range && range.length == 2 ? [
7460
+ range[0],
7461
+ range[1]
7462
+ ] : [await nvim.eval('line(".")')];
7463
+ if (this.doc.filetype == "markdown") {
7464
+ let line = await nvim.call("getline", ["."]);
7465
+ if (line.startsWith("#")) {
7466
+ let words = line.replace(/^#+\s*/, "").split(/\s+/);
7467
+ lines = words.map((s) => s.toLowerCase()).join("-");
7468
+ }
7469
+ }
7470
+ let output = await this.repo.safeRun(["remote"]);
7471
+ if (!output.trim()) {
7472
+ import_coc11.window.showWarningMessage(`No remote found`);
7473
+ return;
7474
+ }
7475
+ let names = output.trim().split(/\r?\n/);
7476
+ let browserRemoteName = config.get("browserRemoteName", "").trim();
7477
+ if (browserRemoteName.length > 0) {
7478
+ if (names.includes(browserRemoteName)) {
7479
+ names = [browserRemoteName];
7480
+ } else {
7481
+ import_coc11.window.showWarningMessage("Configured git.browserRemoteName missing from remote list");
7482
+ return;
7483
+ }
7484
+ }
7485
+ let urls = [];
7486
+ for (let name of names) {
7487
+ let uri = await this.repo.safeRun(["config", "--get", `remote.${name}.url`]);
7488
+ if (!uri.length) continue;
7489
+ let repoURL = getRepoUrl(uri);
7490
+ if (!repoURL) continue;
7491
+ let tmp;
7492
+ try {
7493
+ tmp = new import_url.URL(repoURL);
7494
+ } catch (_e) {
7495
+ continue;
7496
+ }
7497
+ let hostname = tmp.hostname;
7498
+ let fix = "|";
7499
+ try {
7500
+ fix = config.get("urlFix")[hostname][permalink ? 1 : 0];
7501
+ } catch (e) {
7502
+ }
7503
+ let url = getUrl(fix, repoURL, permalink ? head : branch || head, toUnixSlash(this.relpath), lines);
7504
+ if (url) urls.push(url);
7505
+ }
7506
+ if (urls.length == 1) {
7507
+ if (action == "open") {
7508
+ await import_coc11.workspace.openResource(urls[0]);
7509
+ } else {
7510
+ nvim.call("setreg", ["+", urls[0]], true);
7511
+ import_coc11.window.showInformationMessage("Copied url to clipboard");
7512
+ }
7513
+ } else if (urls.length > 1) {
7514
+ let url = await import_coc11.window.showQuickPick(urls, { canPickMany: false, title: "Pick remote url" });
7515
+ if (url) {
7516
+ if (action == "open") {
7517
+ await import_coc11.workspace.openResource(url);
7518
+ } else {
7519
+ nvim.call("setreg", ["+", url], true);
7520
+ nvim.call("setreg", ["*", url], true);
7521
+ import_coc11.window.showInformationMessage("Copied url to clipboard");
7522
+ }
7523
+ }
7524
+ }
7259
7525
  }
7260
- options = options || {};
7261
- const rnds = (_c = (_b = options.random) != null ? _b : (_a = options.rng) == null ? void 0 : _a.call(options)) != null ? _c : rng();
7262
- if (rnds.length < 16) {
7263
- throw new Error("Random bytes length must be >= 16");
7526
+ // show commit of current line in split window
7527
+ async showCommit(useFloating = false) {
7528
+ var _a;
7529
+ let indexed = await this.repo.isIndexed(this.relpath);
7530
+ if (!indexed) {
7531
+ import_coc11.window.showWarningMessage(`"${this.relpath}" not indexed.`);
7532
+ return;
7533
+ }
7534
+ let nvim = import_coc11.workspace.nvim;
7535
+ let line = await nvim.eval('line(".")');
7536
+ let args = ["--no-pager", "blame", "-w", "--porcelain", "--root", `-L${line},${line}`, "--", this.relpath];
7537
+ let res = await this.repo.exec(args);
7538
+ let output = res.stdout.trim();
7539
+ if (!output.length) return;
7540
+ let match = output.match(/^(\S+)\s+(\d+)/);
7541
+ if (!match) return;
7542
+ let commit = match[1];
7543
+ let commitLine = Number(match[2]);
7544
+ if (/^0+$/.test(commit)) {
7545
+ import_coc11.window.showWarningMessage("not committed yet!");
7546
+ return;
7547
+ }
7548
+ if (!useFloating) useFloating = this.config.showCommitInFloating;
7549
+ if (useFloating) {
7550
+ let content = await this.repo.safeRun(["--no-pager", "show", commit]);
7551
+ if (content == null) return;
7552
+ await this.showDoc(content.trim());
7553
+ return;
7554
+ }
7555
+ await nvim.command(`keepalt above ${this.config.splitWindowCommand}`);
7556
+ let hasFugitive = await nvim.eval('get(g:, "loaded_fugitive", 0)');
7557
+ if (hasFugitive) {
7558
+ await nvim.command(`Gedit ${commit}`);
7559
+ let lines = await nvim.call("getline", [1, "$"]);
7560
+ let target = findCommitLine(lines, this.relpath, commitLine);
7561
+ if (target) await nvim.call("cursor", [target, 1]);
7562
+ } else {
7563
+ let content = await this.repo.safeRun(["--no-pager", "show", commit]);
7564
+ if (content == null) return;
7565
+ let lines = content.trim().split("\n");
7566
+ let target = (_a = findCommitLine(lines, this.relpath, commitLine)) != null ? _a : 1;
7567
+ nvim.pauseNotification();
7568
+ nvim.command(`edit +setl\\ buftype=nofile [commit ${commit}]`, true);
7569
+ nvim.command("setl foldmethod=syntax nobuflisted bufhidden=wipe", true);
7570
+ nvim.command("setf git", true);
7571
+ nvim.call("append", [0, lines], true);
7572
+ nvim.command("normal! Gdd", true);
7573
+ nvim.command(`exe ${target}`, true);
7574
+ await nvim.resumeNotification(false, true);
7575
+ }
7264
7576
  }
7265
- rnds[6] = rnds[6] & 15 | 64;
7266
- rnds[8] = rnds[8] & 63 | 128;
7267
- if (buf) {
7268
- offset = offset || 0;
7269
- if (offset < 0 || offset + 16 > buf.length) {
7270
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
7577
+ async toggleFold() {
7578
+ let { nvim } = import_coc11.workspace;
7579
+ let buf = this.doc.buffer;
7580
+ let win = await nvim.window;
7581
+ let bufnr = buf.id;
7582
+ let doc = import_coc11.workspace.getDocument(bufnr);
7583
+ if (!doc) return;
7584
+ let infos = this.currentSigns;
7585
+ if (!infos || infos.length == 0) {
7586
+ import_coc11.window.showWarningMessage("No changes");
7587
+ return;
7271
7588
  }
7272
- for (let i = 0; i < 16; ++i) {
7273
- buf[offset + i] = rnds[i];
7589
+ let changedLines = new Set(infos.map((o) => o.line));
7590
+ let foldContext = this.config.foldContext;
7591
+ let max = this.doc.lineCount;
7592
+ let ranges = [];
7593
+ let start = null;
7594
+ const addRange = (from, to) => {
7595
+ let s = plus(from, foldContext, max);
7596
+ let e = minus(to, foldContext, 0);
7597
+ if (e - s <= 0) return;
7598
+ ranges.push([s, e]);
7599
+ };
7600
+ for (let i = 1; i <= doc.lineCount; i++) {
7601
+ let fold = !changedLines.has(i);
7602
+ if (fold && start == null) {
7603
+ start = i;
7604
+ continue;
7605
+ }
7606
+ if (start != null && !fold) {
7607
+ addRange(start, i - 1);
7608
+ start = null;
7609
+ }
7610
+ if (start != null && fold && i == doc.lineCount) {
7611
+ addRange(start, i);
7612
+ }
7613
+ }
7614
+ let enabled = this.foldEnabled;
7615
+ if (enabled) {
7616
+ this.foldEnabled = false;
7617
+ let cursor = await nvim.eval('getpos(".")');
7618
+ let lnums = ranges.map((o) => o[0]);
7619
+ let settings = this.foldSettings;
7620
+ nvim.pauseNotification();
7621
+ for (let lnum of lnums) {
7622
+ nvim.command(`${lnum}normal! zd`, true);
7623
+ }
7624
+ win.setOption("foldmethod", settings.foldmethod, true);
7625
+ win.setOption("foldenable", settings.foldenable, true);
7626
+ win.setOption("foldlevel", settings.foldlevel, true);
7627
+ nvim.call("setpos", [".", cursor], true);
7628
+ await nvim.resumeNotification();
7629
+ } else {
7630
+ this.foldEnabled = true;
7631
+ let [foldmethod, foldenable, foldlevel] = await nvim.eval("[&foldmethod,&foldenable,&foldlevel]");
7632
+ this.foldSettings = {
7633
+ foldmethod,
7634
+ foldenable: foldenable !== 0,
7635
+ foldlevel
7636
+ };
7637
+ nvim.pauseNotification();
7638
+ win.setOption("foldmethod", "manual", true);
7639
+ nvim.command("silent! normal! zE", true);
7640
+ win.setOption("foldenable", true, true);
7641
+ win.setOption("foldlevel", 0, true);
7642
+ await nvim.resumeNotification();
7643
+ nvim.pauseNotification();
7644
+ for (let r of ranges) {
7645
+ nvim.command(`${r[0]},${r[1]}fold`, true);
7646
+ }
7647
+ await nvim.resumeNotification();
7274
7648
  }
7275
- return buf;
7276
7649
  }
7277
- return unsafeStringify(rnds);
7278
- }
7279
- var v4_default = v4;
7280
-
7281
- // src/model/repo.ts
7282
- var Repo = class {
7283
- constructor(git, channel, root) {
7284
- this.git = git;
7285
- this.channel = channel;
7286
- this.root = root;
7650
+ async toggleGutters(enabled) {
7651
+ this.config.enableGutters = enabled;
7652
+ let { nvim } = import_coc11.workspace;
7653
+ if (!enabled) {
7654
+ nvim.call("sign_unplace", [signGroup, { buffer: this.doc.bufnr }], true);
7655
+ nvim.redrawVim();
7656
+ } else {
7657
+ this.diffs = [];
7658
+ await this.diffDocument(true);
7659
+ }
7287
7660
  }
7288
- /**
7289
- * Get staged info
7290
- */
7291
- async getStagedChunks(relpath) {
7292
- let args = ["-c", "core.quotepath=false", "--no-pager", "diff", "--no-ext-diff", "--no-renames", "-p", "-U0", "--no-color", "--staged"];
7293
- if (relpath) args.push("--", toUnixSlash(relpath));
7294
- const result = await this.exec(args);
7295
- if (!result.stdout) {
7296
- return {};
7661
+ async parseConflicts() {
7662
+ if (!this.config.conflict.enabled) {
7663
+ if (this.conflicts.length) {
7664
+ this.conflicts = [];
7665
+ await this.highlightConflicts([]);
7666
+ }
7667
+ return;
7297
7668
  }
7298
- let res = {};
7299
- let idx = 0;
7300
- let lines = result.stdout.split(/\r?\n/);
7301
- let curr;
7302
- let fsPath;
7303
- while (idx < lines.length) {
7304
- let line = lines[idx];
7305
- if (fsPath && line.startsWith("@@")) {
7306
- curr = void 0;
7307
- let ms = line.match(/^@@\s+-(\d+),?(\d*)\s+\+(\d+),?(\d*)\s+@@/);
7308
- if (ms) {
7309
- curr = {
7310
- remove: { lnum: Number(ms[1]), count: ms[2] ? Number(ms[2]) : 1 },
7311
- add: { lnum: Number(ms[3]), count: ms[4] ? Number(ms[4]) : 1 },
7312
- lines: []
7313
- };
7314
- res[fsPath] = res[fsPath] || [];
7315
- res[fsPath].push(curr);
7669
+ if (!this.hasConflicts && !this.conflictCheckNeeded) return;
7670
+ this.conflictCheckNeeded = false;
7671
+ this.hasConflicts = await this.repo.hasConflicts(this.relpath);
7672
+ if (this._disposed) return;
7673
+ if (!this.hasConflicts) {
7674
+ this.conflicts = [];
7675
+ await this.highlightConflicts([]);
7676
+ return;
7677
+ }
7678
+ const lines = this.doc.textDocument.lines;
7679
+ let conflicts = [];
7680
+ let conflict = null;
7681
+ let state = 0 /* Initial */;
7682
+ let mkStartConflict = (index, current) => ({
7683
+ start: index + 1,
7684
+ sep: 0,
7685
+ end: 0,
7686
+ current,
7687
+ incoming: ""
7688
+ });
7689
+ lines.forEach((line, index) => {
7690
+ switch (state) {
7691
+ case 0 /* Initial */: {
7692
+ const match = line.match(startPattern);
7693
+ if (match) {
7694
+ conflict = mkStartConflict(index, match[1]);
7695
+ state = 1 /* MatchedStart */;
7696
+ }
7697
+ break;
7698
+ }
7699
+ case 2 /* MatchedCommon */:
7700
+ case 1 /* MatchedStart */: {
7701
+ let match = line.match(sepPattern);
7702
+ if (match) {
7703
+ conflict.sep = index + 1;
7704
+ state = 3 /* MatchedSep */;
7705
+ } else {
7706
+ const startMatch = line.match(startPattern);
7707
+ if (startMatch) {
7708
+ conflict = mkStartConflict(index, startMatch[1]);
7709
+ state = 1 /* MatchedStart */;
7710
+ } else if (line.match(endPattern)) {
7711
+ conflict = null;
7712
+ state = 0 /* Initial */;
7713
+ } else if (line.match(commonPattern)) {
7714
+ conflict.common = index + 1;
7715
+ state = 2 /* MatchedCommon */;
7716
+ }
7717
+ }
7718
+ break;
7316
7719
  }
7317
- } else if (curr && /^[+\-]/.test(line)) {
7318
- curr.lines.push(line);
7319
- } else if (line.startsWith("diff --git")) {
7320
- const parsedPath = parseDiffPath(line);
7321
- if (relpath || parsedPath) {
7322
- fsPath = relpath ? toUnixSlash(relpath) : parsedPath;
7323
- curr = void 0;
7324
- idx += 4;
7325
- continue;
7720
+ case 3 /* MatchedSep */: {
7721
+ const match = line.match(endPattern);
7722
+ if (match) {
7723
+ conflict.end = index + 1;
7724
+ conflict.incoming = match[1];
7725
+ conflicts.push(conflict);
7726
+ conflict = null;
7727
+ state = 0 /* Initial */;
7728
+ } else {
7729
+ const startMatch = line.match(startPattern);
7730
+ if (startMatch) {
7731
+ conflict = mkStartConflict(index, startMatch[1]);
7732
+ state = 1 /* MatchedStart */;
7733
+ } else if (line.match(sepPattern)) {
7734
+ conflict = null;
7735
+ state = 0 /* Initial */;
7736
+ }
7737
+ }
7738
+ break;
7326
7739
  }
7327
7740
  }
7328
- idx++;
7329
- }
7330
- return res;
7331
- }
7332
- async getHEAD() {
7333
- try {
7334
- const result = await this.exec(["symbolic-ref", "--short", "HEAD"]);
7335
- if (!result.stdout) {
7336
- throw new Error("Not in a branch");
7337
- }
7338
- return result.stdout.trim();
7339
- } catch (err) {
7340
- const result = await this.exec(["rev-parse", "HEAD"]);
7341
- if (!result.stdout) {
7342
- throw new Error("Error parsing HEAD");
7343
- }
7344
- return result.stdout.trim();
7741
+ });
7742
+ this.conflicts = conflicts;
7743
+ await this.highlightConflicts(conflicts);
7744
+ if (conflicts.length == 0) {
7745
+ this.hasConflicts = false;
7345
7746
  }
7346
7747
  }
7347
- async hasChanged() {
7348
- let result = await this.exec(["diff", "--name-status"]);
7349
- return result.stdout.trim().length > 0;
7350
- }
7351
- async getStaged() {
7352
- let result = await this.exec(["diff", "--staged", "--name-status"]);
7353
- if (!result.stdout) return [0, 0];
7354
- let lines = result.stdout.trim().split(/\r?\n/);
7355
- let conflicted = 0;
7356
- let staged = 0;
7357
- lines.forEach((line) => {
7358
- if (!line.length) return;
7359
- if (line.startsWith("U")) {
7360
- conflicted++;
7361
- } else {
7362
- staged++;
7748
+ async highlightConflicts(conflicts) {
7749
+ if (this._disposed) return;
7750
+ let buffer = this.doc.buffer;
7751
+ let currentHlGroup = this.config.conflict.currentHlGroup;
7752
+ let incomingHlGroup = this.config.conflict.incomingHlGroup;
7753
+ let commonHlGroup = this.config.conflict.commonHlGroup;
7754
+ let { nvim } = import_coc11.workspace;
7755
+ nvim.pauseNotification();
7756
+ buffer.clearNamespace(this.config.conflictSrcId, 0, -1);
7757
+ const srcId = this.config.conflictSrcId;
7758
+ conflicts.map((conflict) => {
7759
+ let currEnd = conflict.common ? conflict.common - 1 : conflict.sep - 1;
7760
+ let currRange = import_coc11.Range.create(import_coc11.Position.create(conflict.start - 1, 0), import_coc11.Position.create(currEnd, 0));
7761
+ let incomingRange = import_coc11.Range.create(import_coc11.Position.create(conflict.sep, 0), import_coc11.Position.create(conflict.end, 0));
7762
+ buffer.highlightRanges(srcId, currentHlGroup, [currRange]);
7763
+ buffer.highlightRanges(srcId, incomingHlGroup, [incomingRange]);
7764
+ if (conflict.common) {
7765
+ let range = import_coc11.Range.create(import_coc11.Position.create(conflict.common - 1, 0), import_coc11.Position.create(conflict.sep - 1, 0));
7766
+ buffer.highlightRanges(srcId, commonHlGroup, [range]);
7363
7767
  }
7364
7768
  });
7365
- return [conflicted, staged];
7366
- }
7367
- async hasUntracked() {
7368
- let cp2 = this.git.stream(this.root, ["ls-files", "--others", "--exclude-standard", "--directory"]);
7369
- return new Promise((resolve) => {
7370
- let settled = false;
7371
- const finish = (value) => {
7372
- if (settled) return;
7373
- settled = true;
7374
- resolve(value);
7375
- };
7376
- cp2.stdout.on("data", () => {
7377
- cp2.kill("SIGKILL");
7378
- finish(true);
7379
- });
7380
- cp2.on("exit", () => {
7381
- finish(false);
7382
- });
7383
- cp2.on("error", () => {
7384
- finish(false);
7385
- });
7386
- });
7769
+ nvim.resumeNotification(false, true);
7387
7770
  }
7388
- async getStatus(character, decorator) {
7389
- try {
7390
- let head = await this.getHEAD();
7391
- if (!head) return "";
7392
- let [changed, staged, untracked] = await Promise.all([this.hasChanged(), this.getStaged(), this.hasUntracked()]);
7393
- const { changedDecorator, conflictedDecorator, stagedDecorator, untrackedDecorator } = decorator;
7394
- let more = "";
7395
- if (changed) more += changedDecorator;
7396
- if (staged[0]) more += conflictedDecorator;
7397
- if (staged[1]) more += stagedDecorator;
7398
- if (untracked) more += untrackedDecorator;
7399
- return `${character ? character + " " : ""}${head}${more}`;
7400
- } catch (e) {
7401
- this.channel.appendLine("Error on git status");
7402
- this.channel.append(e.message);
7403
- return "";
7771
+ async showDoc(content, filetype = "diff") {
7772
+ if (this.floatFactory) {
7773
+ let docs = [{ content, filetype }];
7774
+ await this.floatFactory.show(docs, this.config.floatConfig);
7775
+ } else {
7776
+ const lines = content.split("\n");
7777
+ import_coc11.workspace.nvim.call("coc#ui#preview_info", [lines, filetype], true);
7404
7778
  }
7405
7779
  }
7406
- async getDiff(relFilepath, content, revision = "", encoding = "utf8") {
7407
- if (relFilepath.startsWith(`.git${import_path6.default.sep}`)) return;
7408
- let staged;
7409
- try {
7410
- let indexed = await this.isIndexed(relFilepath);
7411
- if (!indexed) return;
7412
- let res = await this.exec(["--no-pager", "show", `${revision}:${toUnixSlash(relFilepath)}`], { encoding });
7413
- staged = res.stdout.replace(/\r?\n$/, "").split(/\r?\n/).join("\n");
7414
- } catch (e) {
7415
- this.channel.append(e.stack);
7416
- return;
7417
- }
7418
- const stagedFile = import_path6.default.join(import_os.default.tmpdir(), `coc-${v4_default()}`);
7419
- const currentFile = import_path6.default.join(import_os.default.tmpdir(), `coc-${v4_default()}`);
7420
- let output;
7421
- try {
7422
- await import_util5.default.promisify(import_fs2.default.writeFile)(stagedFile, staged + "\n", "utf8");
7423
- await import_util5.default.promisify(import_fs2.default.writeFile)(currentFile, content, "utf8");
7424
- const result = await this.exec([
7425
- "--no-pager",
7426
- "diff",
7427
- "--no-index",
7428
- "--no-ext-diff",
7429
- "-p",
7430
- "-U0",
7431
- "--no-color",
7432
- stagedFile,
7433
- currentFile
7434
- ], { allowedExitCodes: [1] });
7435
- output = result.stdout;
7436
- } finally {
7437
- await Promise.all([
7438
- import_util5.default.promisify(import_fs2.default.unlink)(stagedFile).catch(() => void 0),
7439
- import_util5.default.promisify(import_fs2.default.unlink)(currentFile).catch(() => void 0)
7440
- ]);
7441
- }
7442
- if (!output) return [];
7443
- this.channel.appendLine(`> git diff ${relFilepath}`);
7444
- const lines = output.replace(/\r?\n$/, "").split(/\r?\n/);
7445
- return parseDiff(lines);
7780
+ setBufferStatus(status) {
7781
+ let exists = this.gitStatus;
7782
+ if (exists == status) return;
7783
+ this.gitStatus = status;
7784
+ let { nvim } = import_coc11.workspace;
7785
+ let buffer = nvim.createBuffer(this.doc.bufnr);
7786
+ nvim.pauseNotification();
7787
+ buffer.setVar("coc_git_status", status, true);
7788
+ nvim.callTimer("coc#util#do_autocmd", ["CocGitStatusChange"], true);
7789
+ nvim.resumeNotification(false, true);
7446
7790
  }
7447
- async getDiffAll(category) {
7448
- let diffGroups = /* @__PURE__ */ new Map();
7449
- let args = ["-c", "core.quotepath=false", "--no-pager", "diff", "--no-ext-diff", "--no-renames", "-p", "-U0", "--no-color"];
7450
- if (category === 0 /* All */) {
7451
- const head = await this.safeRun(["rev-parse", "--verify", "HEAD"]);
7452
- if (head) {
7453
- args.push("HEAD");
7454
- } else {
7455
- const emptyTree = await this.exec(["hash-object", "-t", "tree", "--stdin"], { input: "", log: false });
7456
- args.push(emptyTree.stdout.trim());
7457
- }
7458
- } else if (category === 1 /* Staged */) {
7459
- args.push("--cached");
7791
+ getSignName(kind, layer) {
7792
+ if (layer === "staged") {
7793
+ switch (kind) {
7794
+ case "add":
7795
+ return "CocGitStagedAdded";
7796
+ case "change":
7797
+ return "CocGitStagedChanged";
7798
+ case "delete":
7799
+ case "topDelete":
7800
+ case "changeDelete":
7801
+ return "CocGitStagedRemoved";
7802
+ }
7803
+ }
7804
+ if (kind === "mixed") return "CocGitMixed";
7805
+ switch (kind) {
7806
+ case "delete":
7807
+ return "CocGitRemoved";
7808
+ case "add":
7809
+ return "CocGitAdded";
7810
+ case "change":
7811
+ return "CocGitChanged";
7812
+ case "topDelete":
7813
+ return "CocGitTopRemoved";
7814
+ case "changeDelete":
7815
+ return "CocGitChangeRemoved";
7460
7816
  }
7461
- let output = (await this.exec(args)).stdout;
7462
- if (!output) return diffGroups;
7463
- const lines = output.replace(/\r?\n$/, "").split(/\r?\n/);
7464
- let lineGroups = /* @__PURE__ */ new Map();
7465
- let file = null;
7466
- for (const line of lines) {
7467
- if (line.startsWith("diff --git")) {
7468
- file = parseDiffPath(line) || null;
7469
- }
7470
- if (file) {
7471
- if (!lineGroups.has(file)) {
7472
- lineGroups.set(file, []);
7473
- }
7474
- lineGroups.get(file).push(line);
7475
- }
7817
+ return "";
7818
+ }
7819
+ get showBlame() {
7820
+ return this.config.addGBlameToVirtualText || this.config.addGBlameToBufferVar;
7821
+ }
7822
+ dispose() {
7823
+ if (this._disposed) return;
7824
+ this._disposed = true;
7825
+ let { nvim } = import_coc11.workspace;
7826
+ let { bufnr } = this.doc;
7827
+ let buffer = nvim.createBuffer(bufnr);
7828
+ nvim.pauseNotification();
7829
+ buffer.setVar("coc_git_status", "", true);
7830
+ buffer.clearNamespace(this.config.conflictSrcId, 0, -1);
7831
+ nvim.call("sign_unplace", [signGroup, { buffer: bufnr }], true);
7832
+ this.invalidateStagedCache();
7833
+ this.refresh.clear();
7834
+ if (this.config.addGBlameToBufferVar) {
7835
+ buffer.setVar("coc_git_blame", "", true);
7476
7836
  }
7477
- for (const [file2, lines2] of lineGroups) {
7478
- let diffs = parseDiff(lines2);
7479
- if (diffs) {
7480
- diffGroups.set(file2, diffs);
7481
- }
7837
+ if (this.config.addGBlameToVirtualText) {
7838
+ buffer.clearNamespace(this.config.virtualTextSrcId);
7482
7839
  }
7483
- return diffGroups;
7484
- }
7485
- async isIgnored(relativePath) {
7486
- let res = await this.exec(["check-ignore", "-q", "--", relativePath], { allowedExitCodes: [1] });
7487
- return res.exitCode === 0;
7840
+ nvim.resumeNotification(false, true);
7841
+ this.foldEnabled = false;
7488
7842
  }
7489
- async hasConflicts(relativePath) {
7490
- let indexed = await this.isIndexed(relativePath);
7491
- if (!indexed) return false;
7492
- let res = await this.exec(["diff", "--staged", "--name-status", "--", relativePath]);
7493
- return res.stdout.trim().startsWith("U");
7843
+ };
7844
+ function plus(val, count, max) {
7845
+ if (!count) return val;
7846
+ val = val + count;
7847
+ return Math.min(max, val);
7848
+ }
7849
+ function minus(val, count, min) {
7850
+ if (!count) return val;
7851
+ val = val - count;
7852
+ return Math.max(min, val);
7853
+ }
7854
+
7855
+ // src/model/git.ts
7856
+ var cp = __toESM(require("child_process"));
7857
+ var import_coc12 = require("coc.nvim");
7858
+ var import_iconv_lite = __toESM(require_lib());
7859
+ var import_path6 = __toESM(require("path"));
7860
+ var Git = class {
7861
+ constructor(gitInfo, channel) {
7862
+ this.gitInfo = gitInfo;
7863
+ this.channel = channel;
7494
7864
  }
7495
- async isIndexed(relpath) {
7496
- let res = await this.exec(["ls-files", "--", relpath]);
7497
- return res.stdout && res.stdout.trim().length > 0;
7865
+ get path() {
7866
+ return this.gitInfo.path;
7498
7867
  }
7499
- async getUsername() {
7500
- if (typeof this.userName === "string") return this.userName;
7501
- try {
7502
- let res = await this.exec(["config", "user.name"]);
7503
- this.userName = res.stdout.trim();
7504
- return this.userName;
7505
- } catch (e) {
7506
- this.userName = "";
7507
- return "";
7868
+ async getRepositoryRoot(repositoryPath) {
7869
+ const result = await this.exec(repositoryPath, ["rev-parse", "--show-toplevel"]);
7870
+ let repoRootPath = import_path6.default.normalize(result.stdout.trim());
7871
+ if (process.platform === "win32" && repoRootPath.startsWith("\\") && !process.env.SHELL) {
7872
+ repoRootPath = repoRootPath.replace(/^\\([^\\]*)\\/, "$1:\\");
7508
7873
  }
7874
+ return repoRootPath;
7509
7875
  }
7510
- async isShallow() {
7511
- try {
7512
- let res = await this.exec(["rev-parse", "--is-shallow-repository"]);
7513
- return res.stdout.trim() === "true";
7514
- } catch (e) {
7515
- return false;
7516
- }
7876
+ async exec(cwd, args, options = {}) {
7877
+ options = Object.assign({ cwd }, options || {});
7878
+ return await this._exec(args, options);
7517
7879
  }
7518
- async exec(args, options = {}) {
7519
- return await this.git.exec(this.root, args, options);
7880
+ stream(cwd, args, options = {}) {
7881
+ options = Object.assign({ cwd }, options || {});
7882
+ return this.spawn(args, options);
7520
7883
  }
7521
- async safeRun(args, options = {}) {
7522
- try {
7523
- let res = await this.exec(args, options);
7524
- return res ? res.stdout.replace(/\s*$/, "") : "";
7525
- } catch (e) {
7526
- return "";
7884
+ async _exec(args, options = {}) {
7885
+ var _a, _b, _c, _d;
7886
+ if ((_a = options.cancellationToken) == null ? void 0 : _a.isCancellationRequested) {
7887
+ throw new Error("Cancelled");
7527
7888
  }
7528
- }
7529
- };
7530
- function readQuotedGitPath(input, start) {
7531
- if (input[start] !== '"') return void 0;
7532
- let value = "";
7533
- for (let index = start + 1; index < input.length; index++) {
7534
- const character = input[index];
7535
- if (character === '"') return { value, end: index + 1 };
7536
- if (character !== "\\") {
7537
- value += character;
7538
- continue;
7889
+ const child = this.spawn(args, options);
7890
+ if (options.input !== void 0) {
7891
+ (_b = child.stdin) == null ? void 0 : _b.on("error", () => {
7892
+ });
7893
+ (_c = child.stdin) == null ? void 0 : _c.end(options.input, "utf8");
7539
7894
  }
7540
- const escaped = input[++index];
7541
- if (escaped == null) return void 0;
7542
- const escapes = {
7543
- a: "\x07",
7544
- b: "\b",
7545
- t: " ",
7546
- n: "\n",
7547
- v: "\v",
7548
- f: "\f",
7549
- r: "\r",
7550
- '"': '"',
7551
- "\\": "\\"
7895
+ const bufferResult = await exec2(child, options.cancellationToken);
7896
+ if (options.log !== false && bufferResult.stderr.length > 0) {
7897
+ this.log(`${bufferResult.stderr}
7898
+ `);
7899
+ }
7900
+ let encoding = options.encoding || "utf8";
7901
+ encoding = import_iconv_lite.default.encodingExists(encoding) ? encoding : "utf8";
7902
+ const result = {
7903
+ exitCode: bufferResult.exitCode,
7904
+ stdout: import_iconv_lite.default.decode(bufferResult.stdout, encoding),
7905
+ stderr: bufferResult.stderr
7552
7906
  };
7553
- if (escapes[escaped] != null) {
7554
- value += escapes[escaped];
7555
- continue;
7907
+ if (bufferResult.exitCode && !((_d = options.allowedExitCodes) == null ? void 0 : _d.includes(bufferResult.exitCode))) {
7908
+ this.channel.appendLine(`Error ${result.exitCode} on: 'git ${args.join(" ")}' in ${options.cwd}`);
7909
+ this.channel.append(result.stderr);
7910
+ this.channel.append(result.stdout);
7911
+ return Promise.reject(new Error("Failed to execute git"));
7556
7912
  }
7557
- if (/[0-7]/.test(escaped)) {
7558
- let octal = escaped;
7559
- while (octal.length < 3 && /[0-7]/.test(input[index + 1] || "")) octal += input[++index];
7560
- value += String.fromCharCode(parseInt(octal, 8));
7561
- continue;
7913
+ return result;
7914
+ }
7915
+ spawn(args, options = {}) {
7916
+ const { input, encoding: _encoding, log: _log, cancellationToken: _cancellationToken, allowedExitCodes: _allowedExitCodes, ...spawnOptions } = options;
7917
+ if (!spawnOptions.stdio && input === void 0) {
7918
+ spawnOptions.stdio = ["ignore", null, null];
7562
7919
  }
7563
- value += escaped;
7920
+ spawnOptions.env = Object.assign({}, process.env, spawnOptions.env || {}, {
7921
+ LC_ALL: "en_US.UTF-8",
7922
+ LANG: "en_US.UTF-8"
7923
+ });
7924
+ if (options.log !== false) {
7925
+ this.log(`> git ${args.join(" ")}
7926
+ `);
7927
+ }
7928
+ return cp.spawn(this.gitInfo.path, args, spawnOptions);
7564
7929
  }
7565
- return void 0;
7566
- }
7567
- function parseDiffPath(line) {
7568
- const prefix = "diff --git ";
7569
- if (!line.startsWith(prefix)) return void 0;
7570
- const value = line.slice(prefix.length);
7571
- if (value.startsWith('"')) {
7572
- const first = readQuotedGitPath(value, 0);
7573
- if (!first) return void 0;
7574
- const secondStart = value.indexOf('"', first.end);
7575
- const second = secondStart === -1 ? void 0 : readQuotedGitPath(value, secondStart);
7576
- if (!second || !first.value.startsWith("a/") || !second.value.startsWith("b/")) return void 0;
7577
- const firstPath = first.value.slice(2);
7578
- return firstPath === second.value.slice(2) ? firstPath : void 0;
7930
+ log(output) {
7931
+ this.channel.append(output);
7579
7932
  }
7580
- if (!value.startsWith("a/")) return void 0;
7581
- const paths = value.slice(2);
7582
- let separator = paths.indexOf(" b/");
7583
- while (separator !== -1) {
7584
- const firstPath = paths.slice(0, separator);
7585
- if (firstPath === paths.slice(separator + 3)) return firstPath;
7586
- separator = paths.indexOf(" b/", separator + 1);
7933
+ };
7934
+ var git_default = Git;
7935
+ async function exec2(child, cancellationToken) {
7936
+ if (!child.stdout || !child.stderr) {
7937
+ throw new Error("Failed to get stdout or stderr from git process.");
7587
7938
  }
7588
- return void 0;
7589
- }
7590
- var repo_default = Repo;
7591
- function parseDiff(diffLines) {
7592
- const allLines = diffLines.slice(4);
7593
- const diffs = [];
7594
- let diff = null;
7595
- for (const line of allLines) {
7596
- if (!line.startsWith("@@")) {
7597
- if (diff) {
7598
- diff.lines.push(line);
7599
- }
7600
- continue;
7601
- }
7602
- let diffKey = line.split("@@", 2)[1].trim();
7603
- const [pres, nows] = diffKey.split(/\s+/).map((str) => str.slice(1).split(","));
7604
- const removed = {
7605
- start: parseInt(pres[0], 10),
7606
- count: parseInt(`${pres[1] || 1}`, 10)
7607
- };
7608
- const added = {
7609
- start: parseInt(nows[0], 10),
7610
- count: parseInt(`${nows[1] || 1}`, 10)
7611
- };
7612
- if (added.count === 0) {
7613
- diff = {
7614
- lines: [],
7615
- start: added.start,
7616
- end: added.start,
7617
- head: line,
7618
- removed,
7619
- added,
7620
- changeType: "delete" /* Delete */
7621
- };
7622
- diffs.push(diff);
7623
- } else if (removed.count === 0) {
7624
- diff = {
7625
- lines: [],
7626
- start: added.start,
7627
- end: added.start + added.count - 1,
7628
- head: line,
7629
- removed,
7630
- added,
7631
- changeType: "add" /* Add */
7632
- };
7633
- diffs.push(diff);
7634
- } else {
7635
- diff = {
7636
- lines: [],
7637
- start: added.start,
7638
- end: added.start + Math.min(added.count, removed.count) - 1,
7639
- head: line,
7640
- removed,
7641
- added,
7642
- changeType: "changed" /* Change */
7643
- };
7644
- diffs.push(diff);
7645
- }
7939
+ if (cancellationToken && cancellationToken.isCancellationRequested) {
7940
+ throw new Error("Cancelled");
7941
+ }
7942
+ const disposables = [];
7943
+ const once = (ee, name, fn) => {
7944
+ ee.once(name, fn);
7945
+ disposables.push(import_coc12.Disposable.create(() => ee.removeListener(name, fn)));
7946
+ };
7947
+ const on = (ee, name, fn) => {
7948
+ ee.on(name, fn);
7949
+ disposables.push(import_coc12.Disposable.create(() => ee.removeListener(name, fn)));
7950
+ };
7951
+ let result = Promise.all([
7952
+ new Promise((c, e) => {
7953
+ once(child, "error", cpErrorHandler(e));
7954
+ once(child, "exit", (code) => c(code != null ? code : -1));
7955
+ }),
7956
+ new Promise((c) => {
7957
+ const buffers = [];
7958
+ on(child.stdout, "data", (b) => buffers.push(b));
7959
+ once(child.stdout, "close", () => c(Buffer.concat(buffers)));
7960
+ }),
7961
+ new Promise((c) => {
7962
+ const buffers = [];
7963
+ on(child.stderr, "data", (b) => buffers.push(b));
7964
+ once(child.stderr, "close", () => c(Buffer.concat(buffers).toString("utf8")));
7965
+ })
7966
+ ]);
7967
+ if (cancellationToken) {
7968
+ const cancellationPromise = new Promise((_, e) => {
7969
+ const disposable = onceEvent(cancellationToken.onCancellationRequested)(() => {
7970
+ try {
7971
+ child.kill();
7972
+ } catch (err) {
7973
+ }
7974
+ e(new Error("Cancelled"));
7975
+ });
7976
+ disposables.push(disposable);
7977
+ });
7978
+ result = Promise.race([result, cancellationPromise]);
7979
+ }
7980
+ try {
7981
+ const [exitCode, stdout, stderr] = await result;
7982
+ return { exitCode, stdout, stderr };
7983
+ } finally {
7984
+ (0, import_coc12.disposeAll)(disposables);
7646
7985
  }
7647
- return diffs;
7648
7986
  }
7649
7987
 
7650
7988
  // src/model/resolver.ts
@@ -8284,4 +8622,3 @@ async function activate(context) {
8284
8622
  activate,
8285
8623
  formatBlameText
8286
8624
  });
8287
- //# sourceMappingURL=index.js.map