Skip to content

Commit 5a54784

Browse files
authored
update version
2 parents f793ba9 + 052351f commit 5a54784

File tree

6 files changed

+164
-196
lines changed

6 files changed

+164
-196
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "code-enhance",
33
"description": "A vscode toolkit that make coding more comfortable.",
4-
"version": "0.1.0",
4+
"version": "0.1.1",
55
"type": "module",
66
"private": true,
77
"engines": {

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ please read [Code of Conduct](./code_of_conduct.md) before commit your code.
1717

1818
## Enhanced git visualization
1919

20-
1. Show committer, relative time and commit summary as the suffix of a line.
21-
2. Show committer, email and absolute time when hover on the suffix.
20+
1. Show author, relative time and commit summary as the suffix of a line.
21+
2. Show author, email and absolute time when hover on the suffix.
2222

2323
## Enhanced color theme for multi-languages
2424

source/extension.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as vscode from "vscode"
2-
import {enableGitLineHistory} from "./git-line-history.js"
2+
import {enableGitLineBlame} from "./git-line-blame.js"
33

44
export function activate(context: vscode.ExtensionContext) {
5-
enableGitLineHistory(context)
5+
enableGitLineBlame(context)
66
}
77

88
export function deactivate() {}

source/git-line-blame.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import {spawn} from "child_process"
2+
import * as vscode from "vscode"
3+
import {format} from "./utils.js"
4+
5+
export function enableGitLineBlame(context: vscode.ExtensionContext) {
6+
context.subscriptions.push(
7+
vscode.window.onDidChangeTextEditorSelection((event) => {
8+
renderGitBlame(event.textEditor)
9+
}),
10+
)
11+
}
12+
13+
function renderGitBlame(editor: vscode.TextEditor) {
14+
const line = editor.document.lineAt(editor.selection.active.line)
15+
if (line.lineNumber >= editor.document.lineCount - 1) {
16+
decoration.clear(editor)
17+
return
18+
}
19+
20+
const path = editor.document.uri
21+
const args = ["blame", "-p", path.path, `-L${line.lineNumber + 1},+1`]
22+
const stream = spawn("git", args, {
23+
cwd: vscode.workspace.getWorkspaceFolder(path).uri.fsPath,
24+
})
25+
26+
stream.stdout.on("data", (data) => renderGitBlameData(editor, line, data))
27+
stream.stderr.on("error", () => {
28+
vscode.window.showWarningMessage(
29+
`Cannot render Git line blame at: ${path}:${line.lineNumber}`,
30+
)
31+
})
32+
}
33+
34+
function renderGitBlameData(
35+
editor: vscode.TextEditor,
36+
line: vscode.TextLine,
37+
data: any,
38+
) {
39+
const blame = new GitLineBlame(data.toString())
40+
const message = blame.formatLine()
41+
const range = new vscode.Range(
42+
line.lineNumber,
43+
line.text.length,
44+
line.lineNumber,
45+
line.text.length + message.length,
46+
)
47+
decoration.updateOptions(editor, {
48+
range,
49+
hoverMessage: blame.formatHover(),
50+
renderOptions: {after: {contentText: message}},
51+
})
52+
}
53+
54+
namespace decoration {
55+
let currentType = vscode.window.createTextEditorDecorationType({
56+
after: {
57+
textDecoration: "none; opacity: 25%",
58+
margin: "0 0 0 1rem",
59+
},
60+
})
61+
62+
let currentOptions: vscode.DecorationOptions[] = []
63+
64+
export function clear(editor: vscode.TextEditor) {
65+
currentOptions = []
66+
editor.setDecorations(currentType, currentOptions)
67+
}
68+
69+
export function updateType(
70+
editor: vscode.TextEditor,
71+
type: vscode.TextEditorDecorationType,
72+
) {
73+
clear(editor)
74+
currentType = type
75+
editor.setDecorations(type, currentOptions)
76+
}
77+
78+
export function updateOptions(
79+
editor: vscode.TextEditor,
80+
option: vscode.DecorationOptions,
81+
) {
82+
clear(editor)
83+
currentOptions = [option]
84+
editor.setDecorations(currentType, currentOptions)
85+
}
86+
}
87+
88+
class GitLineBlame {
89+
readonly committed: boolean
90+
readonly author: string
91+
readonly authorMail: string
92+
readonly authorTime: number
93+
readonly authorTimeZone: string
94+
readonly summary: string
95+
96+
constructor(raw: string) {
97+
const map = this.map(raw)
98+
this.author = map["author"]
99+
this.authorMail = map["author-mail"]
100+
this.authorTime = parseInt(map["author-time"])
101+
this.authorTimeZone = map["author-tz"]
102+
this.summary = map["summary"]
103+
104+
this.committed = this.author !== "Not Committed Yet"
105+
}
106+
107+
private map(raw: string) {
108+
const lines = raw.split("\n")
109+
lines[0] = `commit-id ${lines[0]}`
110+
lines[lines.length - 1] = `content ${lines[lines.length - 1]}`
111+
112+
const handler = {}
113+
for (const line of lines) {
114+
const parts = line.split(" ")
115+
handler[parts[0]] = parts.slice(1).join(" ")
116+
}
117+
return handler
118+
}
119+
120+
formatLine(): string {
121+
if (!this.committed) return "Not Committed Yet..."
122+
const duration = format.duration(Date.now() - this.authorTime * 1000)
123+
return `${this.author}, ${duration}${this.summary}`
124+
}
125+
126+
formatHover(): string {
127+
if (!this.committed) return "Not Committed Yet..."
128+
return (
129+
`${this.author} <${this.authorMail}>, ` +
130+
`${format.timestamp(this.authorTime * 1000)} ${this.authorTimeZone}`
131+
)
132+
}
133+
}

source/git-line-history.ts

Lines changed: 0 additions & 178 deletions
This file was deleted.

source/utils.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
1-
export function formatTime(timestamp: number) {
2-
const time = new Date(timestamp)
3-
const year = time.getFullYear()
4-
const month = time.getMonth() + 1
5-
const date = time.getDate()
6-
const weekday = time.getDay()
7-
const hours = time.getHours()
8-
const minutes = format2(time.getMinutes())
9-
return `${year}.${month}.${date}(${weekday}) ${hours}:${minutes}`
10-
}
1+
export namespace format {
2+
export function duration(milliseconds: number) {
3+
if (milliseconds < 1000) return `${milliseconds}ms`
4+
milliseconds = Math.floor(milliseconds / 1000)
5+
if (milliseconds < 60) return `${milliseconds}s`
6+
milliseconds = Math.floor(milliseconds / 60)
7+
if (milliseconds < 60) return `${milliseconds}min`
8+
milliseconds = Math.floor(milliseconds / 60)
9+
if (milliseconds < 24) return `${milliseconds}hours`
10+
milliseconds = Math.floor(milliseconds / 24)
11+
if (milliseconds < 31) return `${milliseconds}days`
12+
milliseconds = Math.floor(milliseconds / 30.5)
13+
if (milliseconds < 12) return `${milliseconds}months`
14+
milliseconds = Math.floor(milliseconds / 12)
15+
return `${milliseconds}years`
16+
}
1117

12-
function format2(raw: number) {
13-
if (raw < 10) return `0${raw}`
14-
else return raw.toString()
18+
export function timestamp(timestamp: number) {
19+
const time = new Date(timestamp)
20+
const year = time.getFullYear()
21+
const month = time.getMonth() + 1
22+
const date = time.getDate()
23+
const weekday = time.getDay()
24+
const hours = time.getHours()
25+
const minutes = time.getMinutes().toString().padStart(2, "0")
26+
return `${year}.${month}.${date}(${weekday}) ${hours}:${minutes}`
27+
}
1528
}

0 commit comments

Comments
 (0)