-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextension.js
More file actions
133 lines (114 loc) · 3.59 KB
/
Copy pathextension.js
File metadata and controls
133 lines (114 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Dependencies
const fs = require("fs").promises
const vscode = require("vscode")
const ignore = require("ignore")
const path = require("path")
// Core
class GitignoreDecorationProvider {
constructor() {
this._onDidChangeFileDecorations = new vscode.EventEmitter()
this.onDidChangeFileDecorations = this._onDidChangeFileDecorations.event
this.ignoreCaches = new Map()
this.sortedCaches = []
this.watchers = []
this.init().catch((err)=>{
console.log("Error:", err)
})
}
async init() {
await this.refreshIgnoreCaches()
this.setupWatchers()
}
async refreshIgnoreCaches() {
this.ignoreCaches.clear()
const workspaceFolders = vscode.workspace.workspaceFolders
if (!workspaceFolders) return
const ignoreFiles = await vscode.workspace.findFiles("**/.gitignore", "**/node_modules/**")
for (const file of ignoreFiles) await this.loadGitignore(file.fsPath)
this.updateSortedCaches()
this._onDidChangeFileDecorations.fire(undefined)
}
async loadGitignore(gitignorePath) {
try {
const content = await fs.readFile(gitignorePath, "utf8")
const ig = ignore().add(content)
this.ignoreCaches.set(path.dirname(gitignorePath), {
ig,
path: gitignorePath
})
} catch {
console.log(`Error loading gitignore ${gitignorePath}:`, err)
}
}
updateSortedCaches() {
this.sortedCaches = Array.from(this.ignoreCaches.entries()).sort((a, b) => b[0].length - a[0].length)
}
setupWatchers() {
this.watchers.forEach(w => w.dispose())
this.watchers = []
const watcher = vscode.workspace.createFileSystemWatcher("**/.gitignore")
watcher.onDidCreate(uri => this.handleGitignoreChange(uri))
watcher.onDidChange(uri => this.handleGitignoreChange(uri))
watcher.onDidDelete(uri => this.handleGitignoreDelete(uri))
this.watchers.push(watcher)
const workspaceWatcher = vscode.workspace.onDidChangeWorkspaceFolders(() => this.refreshIgnoreCaches())
this.watchers.push(workspaceWatcher)
}
async handleGitignoreChange(uri) {
await this.loadGitignore(uri.fsPath)
this.updateSortedCaches()
this._onDidChangeFileDecorations.fire(undefined)
}
handleGitignoreDelete(uri) {
this.ignoreCaches.delete(path.dirname(uri.fsPath))
this.updateSortedCaches()
this._onDidChangeFileDecorations.fire(undefined)
}
provideFileDecoration(uri) {
if (uri.scheme !== "file") return
const fsPath = uri.fsPath
for (const [dir, cache] of this.sortedCaches) {
if (fsPath.startsWith(dir)) {
const relativePath = path.relative(dir, fsPath)
if (relativePath && !relativePath.startsWith("..")) {
const normalizedPath = relativePath.split(path.sep).join("/")
const result = cache.ig.test(normalizedPath)
if (result.ignored) {
return {
badge: "GI",
tooltip: "Ignored by .gitignore",
color: new vscode.ThemeColor("errorForeground"),
propagate: true
}
} else if (result.unignored) {
return null
}
}
}
}
return null
}
dispose() {
this.watchers.forEach(w => w.dispose())
this._onDidChangeFileDecorations.dispose()
}
}
// Main
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
console.log("gitignore-marker is now active.")
const decorationProvider = new GitignoreDecorationProvider()
context.subscriptions.push(vscode.window.registerFileDecorationProvider(decorationProvider))
context.subscriptions.push(decorationProvider)
const refreshCommand = vscode.commands.registerCommand("gitignore-marker.refresh", () => {
decorationProvider.refreshIgnoreCaches()
})
context.subscriptions.push(refreshCommand)
}
function deactivate() {}
module.exports = {
activate,
deactivate
}