Skip to content

Commit 9b5165d

Browse files
cometkimarcanis
andauthored
fix(pnpify): make go to definition work with coc.nvim (#2598)
* fix(pnpify): make go to definition work with coc.nvim * minor * fix the template * Update base.ts * fix * handle virtual path correctly * pnpify self * extract predicate for virtual path * pnpify self * normalize paths * cleanup Co-authored-by: Maël Nison <[email protected]>
1 parent 2cc2cd9 commit 9b5165d

File tree

5 files changed

+83
-32
lines changed

5 files changed

+83
-32
lines changed

.vim/coc-settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"eslint.packageManager": "yarn",
3+
"eslint.nodePath": ".yarn/sdks",
4+
"workspace.workspaceFolderCheckCwd": false,
5+
"tsserver.tsdk": ".yarn/sdks/typescript/lib"
6+
}

.yarn/sdks/integrations.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33

44
integrations:
55
- vscode
6+
- vim

.yarn/sdks/typescript/lib/tsserver.js

+34-16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ const moduleWrapper = tsserver => {
1313
const {isAbsolute} = require(`path`);
1414
const pnpApi = require(`pnpapi`);
1515

16+
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
17+
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
18+
1619
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
1720
return `${locator.name}@${locator.reference}`;
1821
}));
@@ -23,7 +26,7 @@ const moduleWrapper = tsserver => {
2326

2427
function toEditorPath(str) {
2528
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
26-
if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || str.match(/\/(\$\$virtual|__virtual__)\//))) {
29+
if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || isVirtual(str))) {
2730
// We also take the opportunity to turn virtual paths into physical ones;
2831
// this makes is much easier to work with workspaces that list peer
2932
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
@@ -34,26 +37,41 @@ const moduleWrapper = tsserver => {
3437
// with peer dep (otherwise jumping into react-dom would show resolution
3538
// errors on react).
3639
//
37-
const resolved = pnpApi.resolveVirtual(str);
40+
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
3841
if (resolved) {
3942
const locator = pnpApi.findPackageLocator(resolved);
4043
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
41-
str = resolved;
44+
str = resolved;
4245
}
4346
}
4447

45-
str = str.replace(/\\/g, `/`)
46-
str = str.replace(/^\/?/, `/`);
48+
str = normalize(str);
4749

48-
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
49-
// VSCode only adds it automatically for supported schemes,
50-
// so we have to do it manually for the `zip` scheme.
51-
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
52-
//
53-
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
54-
//
5550
if (str.match(/\.zip\//)) {
56-
str = `${isVSCode ? `^` : ``}zip:${str}`;
51+
switch (hostInfo) {
52+
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
53+
// VSCode only adds it automatically for supported schemes,
54+
// so we have to do it manually for the `zip` scheme.
55+
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
56+
//
57+
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
58+
//
59+
case `vscode`: {
60+
str = `^zip:${str}`;
61+
} break;
62+
63+
// To make "go to definition" work,
64+
// We have to resolve the actual file system path from virtual path
65+
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
66+
case `coc-nvim`: {
67+
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
68+
str = resolve(`zipfile:${str}`);
69+
} break;
70+
71+
default: {
72+
str = `zip:${str}`;
73+
} break;
74+
}
5775
}
5876
}
5977

@@ -86,7 +104,7 @@ const moduleWrapper = tsserver => {
86104

87105
const Session = tsserver.server.Session;
88106
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
89-
let isVSCode = false;
107+
let hostInfo = `unknown`;
90108

91109
return Object.assign(Session.prototype, {
92110
onMessage(/** @type {string} */ message) {
@@ -96,9 +114,9 @@ const moduleWrapper = tsserver => {
96114
parsedMessage != null &&
97115
typeof parsedMessage === `object` &&
98116
parsedMessage.arguments &&
99-
parsedMessage.arguments.hostInfo === `vscode`
117+
typeof parsedMessage.arguments.hostInfo === `string`
100118
) {
101-
isVSCode = true;
119+
hostInfo = parsedMessage.arguments.hostInfo;
102120
}
103121

104122
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {

.yarn/versions/18b674ec.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
releases:
2+
"@yarnpkg/pnpify": minor
3+
4+
declined:
5+
- "@yarnpkg/plugin-node-modules"
6+
- vscode-zipfs
7+
- "@yarnpkg/builder"
8+
- "@yarnpkg/cli"

packages/yarnpkg-pnpify/sources/sdks/base.ts

+34-16
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ export const generateTypescriptBaseWrapper: GenerateBaseWrapper = async (pnpApi:
4040
const {isAbsolute} = require(\`path\`);
4141
const pnpApi = require(\`pnpapi\`);
4242
43+
const isVirtual = str => str.match(/\\/(\\$\\$virtual|__virtual__)\\//);
44+
const normalize = str => str.replace(/\\\\/g, \`/\`).replace(/^\\/?/, \`/\`);
45+
4346
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
4447
return \`\${locator.name}@\${locator.reference}\`;
4548
}));
@@ -50,7 +53,7 @@ export const generateTypescriptBaseWrapper: GenerateBaseWrapper = async (pnpApi:
5053
5154
function toEditorPath(str) {
5255
// We add the \`zip:\` prefix to both \`.zip/\` paths and virtual paths
53-
if (isAbsolute(str) && !str.match(/^\\^zip:/) && (str.match(/\\.zip\\//) || str.match(/\\/(\\$\\$virtual|__virtual__)\\//))) {
56+
if (isAbsolute(str) && !str.match(/^\\^zip:/) && (str.match(/\\.zip\\//) || isVirtual(str))) {
5457
// We also take the opportunity to turn virtual paths into physical ones;
5558
// this makes is much easier to work with workspaces that list peer
5659
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
@@ -61,26 +64,41 @@ export const generateTypescriptBaseWrapper: GenerateBaseWrapper = async (pnpApi:
6164
// with peer dep (otherwise jumping into react-dom would show resolution
6265
// errors on react).
6366
//
64-
const resolved = pnpApi.resolveVirtual(str);
67+
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
6568
if (resolved) {
6669
const locator = pnpApi.findPackageLocator(resolved);
6770
if (locator && dependencyTreeRoots.has(\`\${locator.name}@\${locator.reference}\`)) {
68-
str = resolved;
71+
str = resolved;
6972
}
7073
}
7174
72-
str = str.replace(/\\\\/g, \`/\`)
73-
str = str.replace(/^\\/?/, \`/\`);
75+
str = normalize(str);
7476
75-
// Absolute VSCode \`Uri.fsPath\`s need to start with a slash.
76-
// VSCode only adds it automatically for supported schemes,
77-
// so we have to do it manually for the \`zip\` scheme.
78-
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
79-
//
80-
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
81-
//
8277
if (str.match(/\\.zip\\//)) {
83-
str = \`\${isVSCode ? \`^\` : \`\`}zip:\${str}\`;
78+
switch (hostInfo) {
79+
// Absolute VSCode \`Uri.fsPath\`s need to start with a slash.
80+
// VSCode only adds it automatically for supported schemes,
81+
// so we have to do it manually for the \`zip\` scheme.
82+
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
83+
//
84+
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
85+
//
86+
case \`vscode\`: {
87+
str = \`^zip:\${str}\`;
88+
} break;
89+
90+
// To make "go to definition" work,
91+
// We have to resolve the actual file system path from virtual path
92+
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
93+
case \`coc-nvim\`: {
94+
str = normalize(resolved).replace(/\\.zip\\//, \`.zip::\`);
95+
str = resolve(\`zipfile:\${str}\`);
96+
} break;
97+
98+
default: {
99+
str = \`zip:\${str}\`;
100+
} break;
101+
}
84102
}
85103
}
86104
@@ -113,7 +131,7 @@ export const generateTypescriptBaseWrapper: GenerateBaseWrapper = async (pnpApi:
113131
114132
const Session = tsserver.server.Session;
115133
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
116-
let isVSCode = false;
134+
let hostInfo = \`unknown\`;
117135
118136
return Object.assign(Session.prototype, {
119137
onMessage(/** @type {string} */ message) {
@@ -123,9 +141,9 @@ export const generateTypescriptBaseWrapper: GenerateBaseWrapper = async (pnpApi:
123141
parsedMessage != null &&
124142
typeof parsedMessage === \`object\` &&
125143
parsedMessage.arguments &&
126-
parsedMessage.arguments.hostInfo === \`vscode\`
144+
typeof parsedMessage.arguments.hostInfo === \`string\`
127145
) {
128-
isVSCode = true;
146+
hostInfo = parsedMessage.arguments.hostInfo;
129147
}
130148
131149
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {

0 commit comments

Comments
 (0)