Skip to content

Commit

Permalink
feat: Line Authoring
Browse files Browse the repository at this point in the history
* Rename getPath to be more informative.

* Added test-vault.

* Added package-lock.json. Added dependencies for line authoring.

* Fix stricter type-errors.

* Line authoring feature.

* feature can be toggled
* submodule support
* follow cut-copy-paste operations and show the original commit where a line was created
* only available on desktops
* file rename support
* configurable in Settings:
    * commit hash, author formatting, date+time formatting
    * max age
    * max and min age colors
        * accessible default colors
    * configure following of cut-copy-paste operations
* view:
    * gutter left to line numbers shows the newest commit where the line was changed
    * Coloring by age
    * multi-line rendered block support (e.g. dataview, <pre>) shows newest commit
    * support for markdown syntax with unequal line-sizes
    * adaptive to dark and light mode
    * copy commit hash with context-menu
    * natural language dates (i.e. 'a week ago')
    * soft and unintrusive updating of the colored gutters when opening new panes
* test-vault:
    * Fake dates in test-vault file for easier testing
* Allows literal filepaths and filepaths with dashes
* robust error handlung

* fix: respect base path

* More features:
* Settings in nested object
* Typescript documentation
* Developer documentation
* feature guide in wiki
* Remove stale subscribers infrequently to reduce load.
* Date format string URL in settings UI

* add deep-equal types

* remove ALLOWSIMPLEGIT global

* remove inflect

* use built in moment

* Added UTC+0 time-zone

* Minor fixes. Improved settings. Added link to feature guide.

* Minior styling improvement.

* fix: middle click to open file/diff in new tab

* feat: prefill edit remote modal

* chore(release): 2.4.0

* fix: keep git view on unload

close #321

* chore(release): 2.4.1

* fix typo (`two` -> `to`)

* Fix copy-able dummy-commit hash

* Line Author Features:

* Performance: avoid dom recomputation and gutter instance re-creation
* Performance: Compute line markers once per action, instead of many times per action
* Added context menu quick configuration
* Adapted to Obsidian v1.0

* Cleanup.

* Fix gutter spacing in Obsidian v1.0

* Fix adaptive coloring, which was broken due to caching.

* Improve wording.

* Fixed first, last and full name display.

* Added option to ignore whitespace and newlines.

* Added quick gutter update of unsaved changes

* Reprioritise

* Fix: messy ui when quick gutter update in empty file or in large vault

* Potential future feature

* update test-vault

* Added setting to set text color css.

* Fix gutter size for empty untracked files

* Updated simple-git to 3.16.0 due to vulnerability

* Show custom line author date format only when applicable.

* refactor: use export

* style: minor formatting

* Simplify moment usage.

* fix: format and fix imports

* remove package-lock.json

* fix moment imports

* remove currentMoment

* better isNewerThan implementation

* remove submodule

* move dev doc

* fix: move git-head-update event to simple git

* remove test log

* link to test-vault

* docs: add line authoring

* docs: add GollyTicker as contributor to readme

* docs: Refactor. Fix link

---------

Co-authored-by: Vinzent <[email protected]>
Co-authored-by: Jakob Hellermann <[email protected]>
  • Loading branch information
3 people authored May 15, 2023
1 parent 782f810 commit aa8dd1b
Show file tree
Hide file tree
Showing 64 changed files with 3,957 additions and 263 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

# npm
node_modules
package-lock.json
main.js
yarn.lock

Expand All @@ -15,4 +14,4 @@ yarn.lock
.prettierrc.json
/data.json

.vscode
.vscode
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ The fastest way to work on mobile if you have a large repo/vault is to stage ind

## Contact

The Line Authoring feature was developed by [GollyTicker](https://github.com/GollyTicker), so any questions may be best answered by him.

If you have any kind of feedback or questions, feel free to reach out via GitHub issues or `@Vinadon` on [Obsidian Discord server](https://discord.com/invite/veuWUTm).

This plugin was initial developed by [denolehov](https://github.com/denolehov). Since March 2021, it is [Vinzent03](https://github.com/Vinzent03) who is developing on this plugin.
Expand Down
1 change: 1 addition & 0 deletions doc/01 Start here.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ aliases:
- [[05 Features|Features]]
- [[06 Tips-and-Tricks|Tips-and-Tricks]]
- [[07 Common issues|Common Issues]]
- [[08 Line Authoring|Line Authoring]]

> [!warning] Obsidian installation on Linux
> Please don't use Flatpak or Snap to install Obsidian on Linux. Learn more [[02 Installation#Linux|here]]
Expand Down
4 changes: 4 additions & 0 deletions doc/05 Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Open it using the "Open Source Control View" command. It lists all current chang

Open it using the "Open History View" command. It behaves like `git log` resulting in a list of the last commits. Each commit entry can be expanded to see the changed files in that commit. By clicking on a file, you can even see the specific diff.

## Line Authoring

For each line, view the last time, it was modified: [[08 Line Authoring|Line Authoring]]. Technically known as `git-blame`.

## Automatic Backup

See [[01 Start here#Backup|Backup]] for an explanation of the term. The goal of automatic Backups is that you can focus on taking notes and not to care about saving your work, because this plugin will take care of it.
Expand Down
165 changes: 165 additions & 0 deletions doc/08 Line Authoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Quick User Guide

A quick showcase of all functionality. This feature is based on [git-blame](https://git-scm.com/docs/git-blame).

ℹ️ The line author view only works in Live-Preview and Source mode - not in Reading mode.

ℹ️ Currently, only Obsidian on desktop is supported.

ℹ️ The recently released Obsidian v1.0 is fully supported. The images and GIFs in this document are however not yet updated.

## Activate

![](assets/line-author-activate.png)

It can also be activated via Command Palette `Obsidian Git: Toggle line author information`.

## Default line author information

![](assets/line-author-default.png)

Shows the initials of the author as well as the authoring date in `YYYY-MM-DD` format.

The `*` indicates, that the author and committer (or their timestamps) are different - i.e., due to a rebase.

## Commit hash and full name

![](assets/line-author-commit-hash-full-name.png)

via config

![](assets/line-author-commit-hash-full-name-config.png)

## Natural language dates

![](assets/line-author-natural-language-dates.png)

## Custom date formats

![](assets/line-author-custom-dates.png)

via config

![](assets/line-author-custom-dates-config.png)

## Commit time in local/author/UTC time-zone

**UTC+0000/Z**

The simplest option to start with is showing the time in `UTC+00:00/Z` time-zone.
This is independent of both your local and the author's time-zone.
It is shown with a suffix `Z` to avoid confusion with local time.

![](assets/line-author-tz-utc0000.png)

This is the time displayed in the guter is the same for all users.

**My local (default)**

By default, the times are shown in your local time-zone - i.e., `What was the clock-time at my wall showing, when the commit was made?` This depends on your local time-zone. For instance, this is the view for a user in the `UTC+01:00` time-zone.

![](assets/line-author-tz-viewer-plus0100.png)

Note, how the displayed time is `1h` ahead of the above `UTC+0000` time.

**Author's local**

Alternatively, it can show it in the author's time-zone with explicit `UTC` offset - i.e., `What was clock-time at the author's wall and their explicit UTC offset, when the commit was made?`

This is independent of your local time-zone and the same time is displayed for all users.

![](assets/line-author-tz-author-local.png)

**Configuration**

![](assets/line-author-tz-config.png)

## Age-based gutter colors

The line gutter color is based on the age of the commit. It adapts to the dark/light mode automatically.

![](assets/line-author-dark-light.gif)

Red-ish means newer and blue-ish means older. All commits at and above a certain maximum coloring
age (configurable; default `1 year`) get the same strongest blue-ish color.

The colors are configurable and the defaults are chosen to be accessible.

![](assets/line-author-color-config.png)

## Adjust text color CSS based on theme

By default, the gutter text color uses `var(--text-muted)` which
is whatever is defined by your theme. You can however, change it to a different CSS
color or variable.

![](assets/line-author-text-color.png)

Example:
| `var(--text-muted)` | `var(--text-normal)` |
|----------------------------------------------|-----------------------------------------------|
| ![](assets/line-author-text-color-muted.png) | ![](assets/line-author-text-color-normal.png) |

## Copy commit hash

![](assets/line-author-copy-commit-hash.png)

## Quick configure gutter

![](assets/line-author-quick-configure-gutter.gif)

## New/uncommitted lines and files show `+++`

![](assets/line-author-untracked.png)

## Follow lines across cut-copy-paste-ing within same commit / all commits

By default, each line shows the last commit, where it was changed.
This means, that cut-copy-paste-ing lines will show the new commit,
even though it was not originally written in that commit.

![](assets/line-author-follow-no-follow.png)

However, if for instance following is set to `all commits`, then this is the result:

![](assets/line-author-follow-all-commits.png)

Configuration:

![](assets/line-author-follow-config.png)

## Soft and unintrusive ansynchronous view updates

Since computing the line author information takes time (due to a `git blame` shell invocation)
the result appears delayed. To minimize distraction and improve user experience,
the view is updated in a soft and unintrusive manner.

When opening a file, a placeholder is shown meanwhile:

![](assets/line-author-soft-unintrusive-ux.gif)

While editing, a placeholder is shown as well until the file is saved and the line author information is computed.

![](assets/line-author-soft-unintrusive-ux-editing.gif)

## Multi-line block support

The markdown rendering of multiple lines as a combined block is also supported.
In this case the newest of all lines is shown in the gutter.

![](assets/line-author-multi-line-newest.gif)

## Ignore whitespace and newlines

This can be activated in the settings.

| **Original** | **Changed with preserved whitespace** | **Changed with ignored whitespace** |
|------------------------------------------------------|-------------------------------------------------------|-------------------------------------------------------|
| ![](assets/line-author-ignore-whitespace-before.png) | ![](assets/line-author-ignore-whitespace-preserved.png) | ![](assets/line-author-ignore-whitespace-ignored.png) |

Note, how ignoring the whitespace does not mark the indented
lines as changes, as only additional whitespace was added.

## Submodules support

Line author information is fully supported in submodules.
Binary file added doc/assets/line-author-activate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-color-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-commit-hash-full-name.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-copy-commit-hash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-custom-dates-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-custom-dates.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-dark-light.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-follow-all-commits.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-follow-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-follow-no-follow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-multi-line-newest.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-natural-language-dates.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-soft-unintrusive-ux.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-text-color-muted.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-text-color-normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-text-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-tz-author-local.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-tz-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/assets/line-author-tz-utc0000.png
Binary file added doc/assets/line-author-tz-viewer-plus0100.png
Binary file added doc/assets/line-author-untracked.png
150 changes: 150 additions & 0 deletions doc/dev/LineAuthorFeature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Line Authoring Feature

Developer documentation.

This feature was developed by [GollyTicker](https://github.com/GollyTicker).

[Feature presentation for users](https://github.com/denolehov/obsidian-git/wiki/Line-Author-Feature).

## Architecture

To understand how this feature integrates with the [Codemirror 6 editor](https://codemirror.net/) used in the Obsidian editors, it is adviseable to read the following sections of the [Codemirror Guide](https://codemirror.net/docs/guide/):
* Architecture Overview > (everything)
* Data Model
* Configuration
* Facets
* Transactions
* View > (intro)
* Extending Codemirror
* State Fields

Furthermore, the following concepts are necessary:
* [EditorState](https://codemirror.net/docs/ref/#state.EditorState)
* [State Field](https://codemirror.net/docs/ref/#state.StateField)
* [Transaction](https://codemirror.net/docs/ref/#state.Transaction)
* [Creating a transaction](https://codemirror.net/docs/ref/#state.EditorState.update)
* [Annotation within a transaction](https://codemirror.net/docs/ref/#state.Annotation)
* [ChangeSet](https://codemirror.net/docs/ref/#state.ChangeSet) (for the unsaved changes gutter update)
* [Exmaple: Document Changes](https://codemirror.net/examples/change/)
* [Example: Configuratoin and Extension](https://codemirror.net/examples/config/)

Given changes/updates of the file or file-view within Obsidian, we want to re-compute the line authoring (via [git-blame](https://git-scm.com/docs/git-blame)) and show it in the line gutters left to the editors.

When doing this, we need to integrate with the declarative modeling of Codemirror - and have its views automatically updated, when we change its associated data.

We achieve the goal via the following steps:
1. Every new editor pane in Obsidian subscribes itself
by its filepath ([LineAuthoringSubcriber](/src/lineAuthor/control.ts))
and listens in an internal publish-subscriber-model
([eventsPerFilepath.ts](/src/lineAuthor/eventsPerFilepath.ts))
for updates on that filepath.
2. Any changed file in the Obsidian Vault or anytime when a new
file is opened, [lineAuthorProvider](/src/lineAuthor/lineAuthoProvider.ts)
initiates the asynchronous computation of the
[LineAuthoring](/src/lineAuthor/model.ts)
via [simpleGit.ts](/src/simpleGit.ts) -
which parses the output of `git-blame`.
3. Once the `LineAuthoring` is computed, the publish-subscriber-model is notified
of the new value for the corresponding filepath.
4. The notified `LineAuthoringSubcriber` creates a new transaction
(via [newComputationResultAsTransaction](/src/lineAuthor/model.ts))
containing the `LineAuthoring`.
5. The `LineAuthoringSubscriber` [dispatches the transaction
on the current EditorView](https://codemirror.net/docs/ref/#view.EditorView.dispatch).
6. The [StateField's update](https://codemirror.net/docs/ref/#state.StateField^define^config.update)
method is called by Codemirror due to the dispatched transaction.
The [lineAuthorState](/src/lineAuthor/model.ts) updates itself with the
newest `LineAuthoring`, if it one was provided in the transaction.
7. The [lineAuthorGutter](/src/lineAuthor/view/view.ts) is automatically re-rendered,
due to the dispatch and the changes of the state-fields. The re-rendering
now accesses the newest state-field values - resulting in a new DOM.

## Development

You can use this test-vault https://github.com/GollyTicker/obsidian-git-test-vault-online.

Once the watchmode npm is started, one can simply open the `test-vault` in Obsidian to
test the plugin. The Obsidian Git plugin files are symbolic links to the
automatically re-compiled files at repository root level.

One can additionally use the
[docker-setup from this branch for a reproduceable developer setup](https://github.com/GollyTicker/obsidian-git/tree/docker-setup).

## Edge cases and error cases

These cases should be tested, when changes to this feature have been made.

* running outside of a git repository
* opening an untracked file
* opening and closing obsidian windows of panes/notes
* notes with a starting "--" in their filename
* special characters in filenames
* unicode filenames
* empty file
* file with populated last line
* multi-line block with differeing line commits
* examples for moving/copy-following
* submodules
* vault root != repository root
* error in git blame result
* open multiple files simultanously
* open same file multiple times - and edit
* open same files in multiple windows - and edit
* open empty tracked file and make edits. quick update should respond sensibly
* open file in a large, complex real-world vault with unknown characteristics
(the private vault of the developer GollyTicker suffices) and repeatedly press Enter in a tracked file.
* We expect no errors, but after adding the unsaved changed gutter update feature,
an early bu was present, where errors would occur during rendering and the view would become messed up.
* UI should render correctly regardless of whether line numbers are shown as well or not.
* [[see obsidan forum discussion](https://forum.obsidian.md/t/added-editor-gutter-overlaps-and-obscures-editor-content/45217)
* indentation changes and changes after last line (without trailing newline) with 'Ignored whitespace' enabled/disabled
* [Unsaved Changes Gutter Update Scenario](#unsaved-changes-gutter-update-scenario)
* commit file in a different time-zone than the current Obsidian user
* check that time-zone "local" formatting is correct
* time-zone "UTC" should always show the same result regardless of the local time-zone
* line authoring id correctly uses submodule HEAD revision rather than super-project.
* There was a bug with the old super-project identifier. It did not fully work with submodules as the following scenario lead to a different displayed line authoring, than the true one.
1. remember the lineAuthoringId A for a file in a submodule in the vault.
* it uses the HEAD of the git super-project rather than of the submodule the file is contained in.
2. add a few lines in the file. The plugin will correctly detect the changed file-contents
hash, which will trigger re-computation and re-render.
3. commit the changes in the submodule - without making a corresponding commit in the super-project.
4. Close the file and re-open it in Obsidian.
* In the submodule, the HEAD has changed - but not in the super-project.
* Since the file path and file contents are same after committing, they haven't changed.
* The current cache key doesn't detect this change and hence the view isn't updated.
* Reloading Obsidian entirely will evict the cache - and the line authoring will be shown correctly again.

### Unsaved Changes Gutter Update Scenario

This scenario contains two main cases to test:

#### 1. Untracked file
1. Open an untracked file. It should show +++ everywhere.
2. Make insertions, deletions and in-line changes. It should always show +++.

#### 2. Tracked file
1. Open a tracked file with different line author dates and colors
2. Make insertions, deletions and in-line changes.
* It should first show % until the changes are saved and the line authoring is computed.
* The % should preserving the color of the changed line and insertions/deletions should shift the
line authoring for subsequent lines accordingly
3. Make multi-line insertions, deletions and in-line changes (e.g. via cut-copy-pasting of blocks of text).
* Hint: Use Ctrl+Z as well.
* The behavior should be same as above.
4. Make changes at the intersection of unsaved and saved changes. The result should be consistent with above.

## Potential Future Improvements

* show commit info when click/hover on gutter
* show / highlight diff when hover/click on gutter
* small tooltip widget when hovering/right-clicking on line author gutter with author/hash, etc.
* show deleted lines
* interpret new 'newline' at end of line as non-change to make gutter change marking more intuitive.
* [one option is to add a setting which switches between compatibility-mode and comfort-mode](https://github.com/denolehov/obsidian-git/pull/288)
* distinguish untracked and changed line (e.g. "~" and "+")
* use addMomentFormat in settings.ts when configuring the line author date format.
* main.ts: refreshUpdatedHead(): Detect, if the head has changed from outside of Obsidian git (e.g. script) and run this callback then.
* Avoid "Uncaught illegal access error" when closing a separate Obsidian window.
It doesn't seem to have any impact on UX yet though...
* Unique initials option: [work in progress branch](https://github.com/GollyTicker/obsidian-git/tree/line-author-unique-initials)
20 changes: 19 additions & 1 deletion esbuild.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,25 @@ const context = await esbuild.context({
},
entryPoints: ["src/main.ts"],
bundle: true,
external: ["obsidian", "electron", "child_process", "fs", "path"],
external: [
'obsidian',
'electron',
'child_process',
'fs',
'path',
'moment',
'@codemirror/autocomplete',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/search',
'@codemirror/state',
'@codemirror/view',
'@lezer/common',
'@lezer/highlight',
'@lezer/lr',
],
format: "cjs",
target: "es2018",
logLevel: "info",
Expand Down
Loading

0 comments on commit aa8dd1b

Please sign in to comment.