-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Diff gutter #1487
Diff gutter #1487
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome this looks very cool!
b.updateDiffSync() | ||
callback(true) | ||
} else if lineCount < 30000 { | ||
b.updateDiffTimer = time.AfterFunc(500*time.Millisecond, func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of the updateDiffTimer
? This will call the given function in a separate goroutine after 500ms. Wouldn't it be better to simply call the function in a separate goroutine right away? Something like
go func() {
b.updateDiffSync()
callback(false)
}()
and then get rid of updateDiffTimer
entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a debounce, a rate-limiting mechanism. It consolidates multiple calls to UpdateDiff
made within a short period of time into a single diff operation. Note that UpdateDiff
returns immediately if a timer is active (i.e., if a diff operation is already scheduled).
As an example, imagine you are editing a file with 20,000 lines (for which a diff operation takes about 30 milliseconds) and typing 10 characters per second. Without the debounce, Micro would perform 10 diff operations per second, taking 300 milliseconds of core time, or 30% of a single CPU core. Additionally, each of these operations would schedule a redraw once it is complete. With the debounce, Micro performs only 2 diff operations and redraws per second, using just 6% of one CPU core.
In other words, this code substantially reduces the CPU usage, at the small price of having to wait a maximum of 0.5 seconds to see diff updates.
@@ -176,6 +176,7 @@ var defaultCommonSettings = map[string]interface{}{ | |||
"basename": false, | |||
"colorcolumn": float64(0), | |||
"cursorline": true, | |||
"diffgutter": true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be false
by default. I'm open to hearing other opinions though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer having it true
by default as in most other editors out there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be disabled by default. I feel like micro should be as simple as possible without configuration. Thought that's my philosophy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe Micro should be as useful as possible without configuration. 99% of programmers use Git, and this feature provides an immediate benefit to them (not having to run git diff
in order to see changes) without negatively impacting anyone else. I am not aware of any editor that has a built-in diff gutter and disables it by default.
I have carefully designed this feature to be as unobtrusive as possible even for people who don't need/want it. The gutter occupies only a single cell of horizontal space. The impact on CPU and memory usage should be minimal (see above). I definitely think this should be a default feature, especially since (to my knowledge) Micro will be the first terminal-based text editor with a built-in diff gutter and displaying this capability by default could raise its popularity. It definitely was one of the first things I missed when I tried out Micro.
I love how this is integrated into micro so well. Seems like a great addition. |
This PR adds a diff indicator gutter that updates as you type, is completely managed by Micro yet can be controlled by plugins:
Background
The VCS diff plugin does not work with the current version of Micro, but that is not the only problem. Like its cousin vim-gitgutter, it shells out to
git diff
, parses the output, and then sets gutter markers in Micro, which is messy and slow. As a result, the plugin only shows the diff when it is explicitly invoked, and does not update until it is invoked again.Solution
This PR takes a different approach by making diffing a first-class function provided by Micro. Plugins only need to set a "diff base", i.e. the text that the buffer is to be diffed against. Everything else, including (re)computing the diff when required and rendering the gutter, is handled automatically by Micro.
This makes creating a Git diff plugin stupidly simple:
Only once, when opening the buffer, does this shell out to Git in order to retrieve the contents of the file from the latest revision. The file system is never again touched afterwards, and in fact the plugin is not involved at all anymore. If Git is not available, or the file is not in Git, diffing falls back to using the file as saved to disk as a base, which matches the behavior of Sublime Text.
I have added this as a default plugin since I imagine that most users would want it and Atom, VSCode, and Sublime all provide this functionality by default as well. Of course, it is trivial to adapt this to other version control systems.
Performance
go-diff is absurdly fast. Computing the full diff between two buffers with 10,000 lines each typically takes only about 15 milliseconds. Buffers with fewer than 1000 lines are handled in less than one millisecond. In order to provide an optimal experience for buffers of any size, this implementation takes an adaptive approach depending on the number of lines:
Color schemes
To support this feature, color schemes need to provide colors for the keys
diff-added
,diff-modified
, anddiff-deleted
. Only the foreground color is used for each of these; the background is set automatically to match that of the corresponding line number.I went through all color schemes shipped with Micro and added appropriate color definitions to each of them. Third-party color schemes will need to be updated separately.