getgrit / gritql

GritQL is a query language for searching, linting, and modifying code.

Home Page:https://docs.grit.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Alternative diff output

morgante opened this issue · comments

Some users like to customize their git diff output.

In theory, grit apply is very similar and we should be able to hook into a pluggable diff output format. Ex. ripgrep seems to work with delta here: https://dandavison.github.io/delta/grep.html

@morgante Not sure I'll be able to help too much on this one as it might be a bit more heft than I can handle at this point. Here's what I've been able to find so far regarding this issue though.

From what I've found Delta works by parsing the output of a stream. If we choose to get things working with other pagers such as Delta then we need to (or at least ned to have the option to) output contents the same as git diff and rg --json does.

git diff filename.txt | delta

Starting with the output of diffs, we can compare our output to that of git.

diff --git a/package.json b/package.json
index 2b3133b..af4a1f8 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
 {
-  "name": "@getgrit/gritql",
+  "name": "DELETE_ME",
   "version": "0.2.2",
   "description": "Core GritQL engine and CLI",
   "author": "",

For readability we need at least the following

  • ---a/filename.txt and +++b/filename.txt for readable filenames
  • @@ -1,5 +1,5 @@ for the before/after line ranges
  • lines should be prepended with -, + or before the whitespace

Let's compare this with our current output

example.js
    -const myVar = 2;
    +let myVar = 2;
    

Processed 1 files and found 1 matches

It's fine to keep the message at the end of the diff. It doesn't start with -, +, or so it doesn't format it.


Now, taking a look at match outputs as a grep format, Delta expects an output formatted like rg --json -C 2 "my-query"

{ "type": "begin", "data": { "path": { "text": "package.json" } } },
{
  "type": "context",
  "data": {
    "path": { "text": "package.json" },
    "lines": { "text": "{\n" },
    "line_number": 1,
    "absolute_offset": 0,
    "submatches": []
  }
},
{
  "type": "match",
  "data": {
    "path": { "text": "package.json" },
    "lines": { "text": "  \"name\": \"DELETE_ME\",\n" },
    "line_number": 2,
    "absolute_offset": 2,
    "submatches": [
      { "match": { "text": "DELETE_ME" }, "start": 11, "end": 20 }
    ]
  }
},
// ...more match/context blocks
{
  "type": "end",
  "data": {
    "path": { "text": "grep-example.txt" },
    "binary_offset": null,
    "stats": {
      "elapsed": { "secs": 0, "nanos": 1656401, "human": "0.001656s" },
      "searches": 1,
      "searches_with_match": 1,
      "bytes_searched": 1260,
      "bytes_printed": 1736,
      "matched_lines": 1,
      "matches": 2
    }
  }
},
// ...more start/end blocks with match/context blocks between
{
  "data": {
    "elapsed_total": { "human": "2.397146s", "nanos": 397145746, "secs": 2 },
    "stats": {
      "bytes_printed": 2477,
      "bytes_searched": 1710,
      "elapsed": { "human": "0.003502s", "nanos": 3502102, "secs": 0 },
      "matched_lines": 2,
      "matches": 3,
      "searches": 2,
      "searches_with_match": 2
    }
  },
  "type": "summary"
}

From messing with this output, it seems the only thing we can omit is the following

  • "type": "summary" blocks

Approaches

There a many ways we could approach this, and we might want to discuss the most appropriate method to do this. We would need to update the formatter to match git diff/grep --json either when

  1. When any output is made;
  2. When an option to --output (eg --output pager) to format according to the needs of Delta;
  3. When grit's stdout is sent to a pipe, format according to the needs of Delta; or
  4. When a configuration option to use a pager such as delta. When given, pipe the output to the specified executable, in the format Delta expects

Caveats

  • Unfortunately, grit doesn't know how to handle diffs and matches being passed to it side-by-side. So the pager may have to be run multiple times as we switch from type to type. This will probably make most approaches listed non-feasible

Thanks for investigating this!

Overall, I think I like the option of starting with an --output=diff flag which will match git diff output. This should be fairly portable, and if I understand correctly, would allow piping into Delta easily.

Once that's implemented, we could consider an --pager flag to handle the piping ourselves.

Unfortunately, grit doesn't know how to handle diffs and matches being passed to it side-by-side. So the pager may have to be run multiple times as we switch from type to type.

Do you mean that delta doesn't support this? For initial implementation, I assume we would only really be interested in diffs.

Yeah what I mean is that we can't mix diffs and grep outputs together. Each type would have to be processed by delta separately.