Skip to content

Commit 9d0cb83

Browse files
authored
feat: add showPreciseDate setting (#220)
1 parent d9e9bd7 commit 9d0cb83

File tree

4 files changed

+110
-51
lines changed

4 files changed

+110
-51
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
"type": "string",
6363
"enum": ["none", "line", "file"],
6464
"default": "none"
65+
},
66+
"git.blame.showPreciseDate": {
67+
"description": "Whether to show precise dates (e.g. \"Mar 17, 2021\"). By default, distance from current date is shown (e.g. \"3 months ago\")",
68+
"type": "boolean",
69+
"default": false
6570
}
6671
}
6772
}

src/blame.test.ts

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ const SOURCEGRAPH = createMockSourcegraphAPI()
8989

9090
describe('getDecorationsFromHunk()', () => {
9191
it('creates a TextDocumentDecoration from a Hunk', () => {
92-
expect(getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, SOURCEGRAPH as any)).toEqual({
92+
expect(
93+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any)
94+
).toEqual({
9395
after: {
9496
contentText: 'a, 3 months ago: • c',
9597
dark: {
@@ -119,6 +121,7 @@ describe('getDecorationsFromHunk()', () => {
119121
},
120122
NOW,
121123
0,
124+
{ 'git.blame.showPreciseDate': false },
122125
SOURCEGRAPH as any
123126
)
124127
expect(decoration.after && decoration.after.contentText).toEqual(
@@ -141,6 +144,7 @@ describe('getDecorationsFromHunk()', () => {
141144
},
142145
NOW,
143146
0,
147+
{ 'git.blame.showPreciseDate': false },
144148
SOURCEGRAPH as any
145149
)
146150
expect(decoration.after && decoration.after.contentText).toEqual(
@@ -155,9 +159,12 @@ describe('getBlameDecorationsForSelections()', () => {
155159
[FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
156160
[new SOURCEGRAPH.Selection(new SOURCEGRAPH.Position(1, 0), new SOURCEGRAPH.Position(1, 0)) as any],
157161
NOW,
162+
{ 'git.blame.showPreciseDate': false },
158163
SOURCEGRAPH as any
159164
)
160-
expect(decorations).toEqual([getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any)])
165+
expect(decorations).toEqual([
166+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
167+
])
161168
})
162169

163170
it('handles multiple selections', () => {
@@ -169,12 +176,13 @@ describe('getBlameDecorationsForSelections()', () => {
169176
new SOURCEGRAPH.Selection(new SOURCEGRAPH.Position(6, 0), new SOURCEGRAPH.Position(10, 0)) as any,
170177
],
171178
NOW,
179+
{ 'git.blame.showPreciseDate': false },
172180
SOURCEGRAPH as any
173181
)
174182
expect(decorations).toEqual([
175-
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any),
176-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any),
177-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any),
183+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
184+
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
185+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
178186
])
179187
})
180188

@@ -183,13 +191,14 @@ describe('getBlameDecorationsForSelections()', () => {
183191
[FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
184192
[new SOURCEGRAPH.Selection(new SOURCEGRAPH.Position(0, 0), new SOURCEGRAPH.Position(5, 0)) as any],
185193
NOW,
194+
{ 'git.blame.showPreciseDate': false },
186195
SOURCEGRAPH as any
187196
)
188197
expect(decorations).toEqual([
189-
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, SOURCEGRAPH as any),
190-
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any),
191-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any),
192-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any),
198+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
199+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
200+
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
201+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
193202
])
194203
})
195204

@@ -204,9 +213,12 @@ describe('getBlameDecorationsForSelections()', () => {
204213
],
205214
[new SOURCEGRAPH.Selection(new SOURCEGRAPH.Position(2, 0), new SOURCEGRAPH.Position(2, 0)) as any],
206215
NOW,
216+
{ 'git.blame.showPreciseDate': false },
207217
SOURCEGRAPH as any
208218
)
209-
expect(decorations).toEqual([getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 2, SOURCEGRAPH as any)])
219+
expect(decorations).toEqual([
220+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
221+
])
210222
})
211223
})
212224

@@ -216,13 +228,14 @@ describe('getAllBlameDecorations()', () => {
216228
getAllBlameDecorations(
217229
[FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
218230
NOW,
231+
{ 'git.blame.showPreciseDate': false },
219232
SOURCEGRAPH as any
220233
)
221234
).toEqual([
222-
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, SOURCEGRAPH as any),
223-
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any),
224-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any),
225-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any),
235+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
236+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
237+
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
238+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
226239
])
227240
})
228241
})
@@ -233,17 +246,18 @@ describe('getBlameDecorations()', () => {
233246
getBlameDecorations({
234247
settings: {
235248
'git.blame.decorations': 'line',
249+
'git.blame.showPreciseDate': false,
236250
},
237251
now: NOW,
238252
selections: null,
239253
hunks: [FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
240254
sourcegraph: SOURCEGRAPH as any,
241255
})
242256
).toEqual([
243-
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, SOURCEGRAPH as any),
244-
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any),
245-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any),
246-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any),
257+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
258+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
259+
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
260+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
247261
])
248262
})
249263

@@ -260,7 +274,9 @@ describe('getBlameDecorations()', () => {
260274
hunks: [FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
261275
sourcegraph: SOURCEGRAPH as any,
262276
})
263-
).toEqual([getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any)])
277+
).toEqual([
278+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
279+
])
264280
})
265281

266282
it('gets no decorations if git.blame.decorations is "none"', async () => {
@@ -291,23 +307,33 @@ describe('getBlameDecorations()', () => {
291307
sourcegraph: SOURCEGRAPH as any,
292308
})
293309
).toEqual([
294-
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, SOURCEGRAPH as any),
295-
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, SOURCEGRAPH as any),
296-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any),
297-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any),
310+
getDecorationFromHunk(FIXTURE_HUNK_1, NOW, 0, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
311+
getDecorationFromHunk(FIXTURE_HUNK_2, NOW, 1, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
312+
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
313+
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, { 'git.blame.showPreciseDate': false }, SOURCEGRAPH as any),
298314
])
299315
})
300316

301317
it('renders username in decoration content message', async () => {
302318
expect(
303-
getDecorationFromHunk(FIXTURE_HUNK_4, NOW, 3, SOURCEGRAPH as any).after!.contentText!.startsWith(
319+
getDecorationFromHunk(
320+
FIXTURE_HUNK_4,
321+
NOW,
322+
3,
323+
{ 'git.blame.showPreciseDate': false },
324+
SOURCEGRAPH as any
325+
).after!.contentText!.startsWith(
304326
`(${FIXTURE_HUNK_4.author.person.user!.username}) ${FIXTURE_HUNK_4.author.person.displayName}`
305327
)
306328
).toBe(true)
307329
expect(
308-
getDecorationFromHunk(FIXTURE_HUNK_3, NOW, 2, SOURCEGRAPH as any).after!.contentText!.startsWith(
309-
`${FIXTURE_HUNK_3.author.person.displayName}`
310-
)
330+
getDecorationFromHunk(
331+
FIXTURE_HUNK_3,
332+
NOW,
333+
2,
334+
{ 'git.blame.showPreciseDate': false },
335+
SOURCEGRAPH as any
336+
).after!.contentText!.startsWith(`${FIXTURE_HUNK_3.author.person.displayName}`)
311337
).toBe(true)
312338
})
313339
})
@@ -321,6 +347,7 @@ describe('getBlameStatusBarItem()', () => {
321347
],
322348
hunks: [FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
323349
sourcegraph: SOURCEGRAPH as any,
350+
settings: { 'git.blame.showPreciseDate': false },
324351
now: NOW,
325352
}).text
326353
).toBe('Author: (testUserName) i, 2 months ago')
@@ -332,6 +359,7 @@ describe('getBlameStatusBarItem()', () => {
332359
selections: [],
333360
hunks: [FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
334361
sourcegraph: SOURCEGRAPH as any,
362+
settings: { 'git.blame.showPreciseDate': false },
335363
now: NOW,
336364
}).text
337365
).toBe('Author: e, 21 days ago')
@@ -341,6 +369,7 @@ describe('getBlameStatusBarItem()', () => {
341369
selections: null,
342370
hunks: [FIXTURE_HUNK_1, FIXTURE_HUNK_2, FIXTURE_HUNK_3, FIXTURE_HUNK_4],
343371
sourcegraph: SOURCEGRAPH as any,
372+
settings: { 'git.blame.showPreciseDate': false },
344373
now: NOW,
345374
}).text
346375
).toBe('Author: e, 21 days ago')

src/blame.ts

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import compareDesc from 'date-fns/compareDesc'
2+
import format from 'date-fns/format'
23
import formatDistanceStrict from 'date-fns/formatDistanceStrict'
34
import { Selection, StatusBarItem, TextDocumentDecoration } from 'sourcegraph'
45
import gql from 'tagged-template-noop'
@@ -9,21 +10,29 @@ import { memoizeAsync } from './util/memoizeAsync'
910
/**
1011
* Get display info shared between status bar items and text document decorations.
1112
*/
12-
const getDisplayInfoFromHunk = (
13-
{ author, commit, message }: Pick<Hunk, 'author' | 'commit' | 'message'>,
14-
now: number,
13+
const getDisplayInfoFromHunk = ({
14+
hunk: { author, commit, message },
15+
now,
16+
settings,
17+
sourcegraph,
18+
}: {
19+
hunk: Pick<Hunk, 'author' | 'commit' | 'message'>
20+
now: number
21+
settings: Pick<Settings, 'git.blame.showPreciseDate'>
1522
sourcegraph: typeof import('sourcegraph')
16-
): { displayName: string; username: string; distance: string; linkURL: string; hoverMessage: string } => {
23+
}): { displayName: string; username: string; dateString: string; linkURL: string; hoverMessage: string } => {
1724
const displayName = truncate(author.person.displayName, 25)
1825
const username = author.person.user ? `(${author.person.user.username}) ` : ''
19-
const distance = formatDistanceStrict(author.date, now, { addSuffix: true })
26+
const dateString = settings['git.blame.showPreciseDate']
27+
? format(author.date, 'MMM dd, y')
28+
: formatDistanceStrict(author.date, now, { addSuffix: true })
2029
const linkURL = new URL(commit.url, sourcegraph.internal.sourcegraphURL.toString()).href
2130
const hoverMessage = `${author.person.email}${truncate(message, 1000)}`
2231

2332
return {
2433
displayName,
2534
username,
26-
distance,
35+
dateString,
2736
linkURL,
2837
hoverMessage,
2938
}
@@ -70,9 +79,15 @@ export const getDecorationFromHunk = (
7079
hunk: Hunk,
7180
now: number,
7281
decoratedLine: number,
82+
settings: Pick<Settings, 'git.blame.showPreciseDate'>,
7383
sourcegraph: typeof import('sourcegraph')
7484
): TextDocumentDecoration => {
75-
const { displayName, username, distance, linkURL, hoverMessage } = getDisplayInfoFromHunk(hunk, now, sourcegraph)
85+
const { displayName, username, dateString, linkURL, hoverMessage } = getDisplayInfoFromHunk({
86+
hunk,
87+
now,
88+
settings,
89+
sourcegraph,
90+
})
7691

7792
return {
7893
range: new sourcegraph.Range(decoratedLine, 0, decoratedLine, 0),
@@ -86,7 +101,7 @@ export const getDecorationFromHunk = (
86101
color: 'rgba(235, 235, 255, 0.55)',
87102
backgroundColor: 'rgba(15, 43, 89, 0.65)',
88103
},
89-
contentText: `${username}${displayName}, ${distance}: • ${truncate(hunk.message, 45)}`,
104+
contentText: `${username}${displayName}, ${dateString}: • ${truncate(hunk.message, 45)}`,
90105
hoverMessage,
91106
linkURL,
92107
},
@@ -97,14 +112,19 @@ export const getBlameDecorationsForSelections = (
97112
hunks: Hunk[],
98113
selections: Selection[],
99114
now: number,
115+
settings: Pick<Settings, 'git.blame.showPreciseDate'>,
100116
sourcegraph: typeof import('sourcegraph')
101117
) =>
102118
getHunksForSelections(hunks, selections).map(({ hunk, selectionStartLine }) =>
103-
getDecorationFromHunk(hunk, now, selectionStartLine, sourcegraph)
119+
getDecorationFromHunk(hunk, now, selectionStartLine, settings, sourcegraph)
104120
)
105121

106-
export const getAllBlameDecorations = (hunks: Hunk[], now: number, sourcegraph: typeof import('sourcegraph')) =>
107-
hunks.map(hunk => getDecorationFromHunk(hunk, now, hunk.startLine - 1, sourcegraph))
122+
export const getAllBlameDecorations = (
123+
hunks: Hunk[],
124+
now: number,
125+
settings: Pick<Settings, 'git.blame.showPreciseDate'>,
126+
sourcegraph: typeof import('sourcegraph')
127+
) => hunks.map(hunk => getDecorationFromHunk(hunk, now, hunk.startLine - 1, settings, sourcegraph))
108128

109129
export const queryBlameHunks = memoizeAsync(
110130
async ({ uri, sourcegraph }: { uri: string; sourcegraph: typeof import('sourcegraph') }): Promise<Hunk[]> => {
@@ -176,35 +196,38 @@ export const getBlameDecorations = ({
176196
return []
177197
}
178198
if (selections !== null && decorations === 'line') {
179-
return getBlameDecorationsForSelections(hunks, selections, now, sourcegraph)
199+
return getBlameDecorationsForSelections(hunks, selections, now, settings, sourcegraph)
180200
} else {
181-
return getAllBlameDecorations(hunks, now, sourcegraph)
201+
return getAllBlameDecorations(hunks, now, settings, sourcegraph)
182202
}
183203
}
184204

185205
export const getBlameStatusBarItem = ({
186206
selections,
187207
hunks,
188208
now,
209+
settings,
189210
sourcegraph,
190211
}: {
191212
selections: Selection[] | null
192213
hunks: Hunk[]
193214
now: number
215+
settings: Pick<Settings, 'git.blame.showPreciseDate'>
194216
sourcegraph: typeof import('sourcegraph')
195217
}): StatusBarItem => {
196218
if (selections && selections.length > 0) {
197219
const hunksForSelections = getHunksForSelections(hunks, selections)
198220
if (hunksForSelections[0]) {
199221
// Display the commit for the first selected hunk in the status bar.
200-
const { displayName, username, distance, linkURL, hoverMessage } = getDisplayInfoFromHunk(
201-
hunksForSelections[0].hunk,
222+
const { displayName, username, dateString, linkURL, hoverMessage } = getDisplayInfoFromHunk({
223+
hunk: hunksForSelections[0].hunk,
202224
now,
203-
sourcegraph
204-
)
225+
settings,
226+
sourcegraph,
227+
})
205228

206229
return {
207-
text: `Author: ${username}${displayName}, ${distance}`,
230+
text: `Author: ${username}${displayName}, ${dateString}`,
208231
command: { id: 'open', args: [linkURL] },
209232
tooltip: hoverMessage,
210233
}
@@ -223,14 +246,15 @@ export const getBlameStatusBarItem = ({
223246
text: 'Author: not found',
224247
}
225248
}
226-
const { displayName, username, distance, linkURL, hoverMessage } = getDisplayInfoFromHunk(
227-
mostRecentHunk.hunk,
249+
const { displayName, username, dateString, linkURL, hoverMessage } = getDisplayInfoFromHunk({
250+
hunk: mostRecentHunk.hunk,
228251
now,
229-
sourcegraph
230-
)
252+
settings,
253+
sourcegraph,
254+
})
231255

232256
return {
233-
text: `Author: ${username}${displayName}, ${distance}`,
257+
text: `Author: ${username}${displayName}, ${dateString}`,
234258
command: { id: 'open', args: [linkURL] },
235259
tooltip: hoverMessage,
236260
}

src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface Settings {
99
// to 'onboard' users to new setting
1010
['git.blame.lineDecorations']?: boolean
1111
['git.blame.decorateWholeFile']?: boolean
12+
['git.blame.showPreciseDate']?: boolean
1213
}
1314

1415
const decorationType = sourcegraph.app.createDecorationType && sourcegraph.app.createDecorationType()
@@ -61,7 +62,7 @@ export function activate(context: sourcegraph.ExtensionContext): void {
6162
if ('setStatusBarItem' in editor) {
6263
editor.setStatusBarItem(
6364
statusBarItemType,
64-
getBlameStatusBarItem({ selections, hunks, now, sourcegraph })
65+
getBlameStatusBarItem({ selections, hunks, now, settings, sourcegraph })
6566
)
6667
}
6768

0 commit comments

Comments
 (0)