Skip to content

Commit 40ae9c2

Browse files
authored
Merge pull request #452 from pranaysashank/master
Fix showDocumentation command.
2 parents f33d636 + b85ec43 commit 40ae9c2

File tree

2 files changed

+109
-45
lines changed

2 files changed

+109
-45
lines changed

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@
9393
"default": "ormolu",
9494
"description": "The formatter to use when formatting a document or range. Ensure the plugin is enabled."
9595
},
96+
"haskell.openDocumentationInHackage": {
97+
"scope": "resource",
98+
"type": "boolean",
99+
"default": true,
100+
"description": "When opening 'Documentation' for external libraries, open in hackage by default. Set to false to instead open in vscode."
101+
},
102+
"haskell.openSourceInHackage": {
103+
"scope": "resource",
104+
"type": "boolean",
105+
"default": true,
106+
"description": "When opening 'Source' for external libraries, open in hackage by default. Set to false to instead open in vscode."
107+
},
96108
"haskell.trace.server": {
97109
"scope": "resource",
98110
"type": "string",

src/docsBrowser.ts

Lines changed: 97 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,56 +16,86 @@ import {
1616
Uri,
1717
ViewColumn,
1818
window,
19+
workspace,
1920
} from 'vscode';
2021
import { ProvideCompletionItemsSignature, ProvideHoverSignature } from 'vscode-languageclient';
2122

2223
export namespace DocsBrowser {
2324
'use strict';
2425

26+
async function showDocumentation({
27+
title,
28+
localPath,
29+
hackageUri,
30+
}: {
31+
title: string;
32+
localPath: string;
33+
hackageUri: string;
34+
}) {
35+
const arr = localPath.match(/([^\/]+)\.[^.]+$/);
36+
const ttl = arr !== null && arr.length === 2 ? arr[1].replace(/-/gi, '.') : title;
37+
const documentationDirectory = dirname(localPath);
38+
let panel;
39+
try {
40+
const docUri = Uri.parse(documentationDirectory);
41+
42+
// Make sure to use Uri.parse here, as path will already have 'file:///' in it
43+
panel = window.createWebviewPanel('haskell.showDocumentationPanel', ttl, ViewColumn.Beside, {
44+
localResourceRoots: [docUri],
45+
enableFindWidget: true,
46+
enableCommandUris: true,
47+
enableScripts: true,
48+
});
49+
50+
const encoded = encodeURIComponent(JSON.stringify({ hackageUri: hackageUri, inWebView: true }));
51+
const hackageCmd = 'command:haskell.openDocumentationOnHackage?' + encoded;
52+
53+
const bytes = await workspace.fs.readFile(Uri.parse(localPath));
54+
55+
const addBase = `
56+
<base href="${panel.webview.asWebviewUri(Uri.parse(documentationDirectory))}/">
57+
`;
58+
59+
panel.webview.html = `
60+
<html>
61+
${addBase}
62+
<body>
63+
<div><a href="${hackageCmd}">Open on Hackage</a></div>
64+
${bytes.toString()}
65+
</body>
66+
</html>
67+
`;
68+
} catch (e) {
69+
await window.showErrorMessage(e);
70+
}
71+
return panel;
72+
}
73+
2574
// registers the browser in VSCode infrastructure
2675
export function registerDocsBrowser(): Disposable {
27-
return commands.registerCommand(
28-
'haskell.showDocumentation',
29-
async ({ title, localPath, hackageUri }: { title: string; localPath: string; hackageUri: string }) => {
30-
const arr = localPath.match(/([^\/]+)\.[^.]+$/);
31-
const ttl = arr !== null && arr.length === 2 ? arr[1].replace(/-/gi, '.') : title;
32-
const documentationDirectory = dirname(localPath);
33-
let panel;
34-
try {
35-
// Make sure to use Uri.parse here, as path will already have 'file:///' in it
36-
panel = window.createWebviewPanel('haskell.showDocumentationPanel', ttl, ViewColumn.Beside, {
37-
localResourceRoots: [Uri.parse(documentationDirectory)],
38-
enableFindWidget: true,
39-
enableCommandUris: true,
40-
});
41-
const uri = panel.webview.asWebviewUri(Uri.parse(localPath));
42-
43-
const encoded = encodeURIComponent(JSON.stringify({ hackageUri }));
44-
const hackageCmd = 'command:haskell.openDocumentationOnHackage?' + encoded;
76+
return commands.registerCommand('haskell.showDocumentation', showDocumentation);
77+
}
4578

46-
panel.webview.html = `<div><a href="${hackageCmd}">Open on Hackage</a></div>
47-
<div><iframe src="${uri}" frameBorder = "0" style = "background: white; width: 100%; height: 100%; position:absolute; left: 0; right: 0; bottom: 0; top: 30px;"/></div>`;
48-
} catch (e) {
49-
await window.showErrorMessage(e);
50-
}
51-
return panel;
79+
async function openDocumentationOnHackage({
80+
hackageUri,
81+
inWebView = false,
82+
}: {
83+
hackageUri: string;
84+
inWebView: boolean;
85+
}) {
86+
try {
87+
// open on Hackage and close the original webview in VS code
88+
await env.openExternal(Uri.parse(hackageUri));
89+
if (inWebView) {
90+
await commands.executeCommand('workbench.action.closeActiveEditor');
5291
}
53-
);
92+
} catch (e) {
93+
await window.showErrorMessage(e);
94+
}
5495
}
5596

5697
export function registerDocsOpenOnHackage(): Disposable {
57-
return commands.registerCommand(
58-
'haskell.openDocumentationOnHackage',
59-
async ({ hackageUri }: { hackageUri: string }) => {
60-
try {
61-
// open on Hackage and close the original webview in VS code
62-
await env.openExternal(Uri.parse(hackageUri));
63-
await commands.executeCommand('workbench.action.closeActiveEditor');
64-
} catch (e) {
65-
await window.showErrorMessage(e);
66-
}
67-
}
68-
);
98+
return commands.registerCommand('haskell.openDocumentationOnHackage', openDocumentationOnHackage);
6999
}
70100

71101
export function hoverLinksMiddlewareHook(
@@ -109,17 +139,39 @@ export namespace DocsBrowser {
109139
}
110140

111141
function processLink(ms: MarkdownString | MarkedString): string | MarkdownString {
142+
const openDocsInHackage = workspace.getConfiguration('haskell').get('openDocumentationInHackage');
143+
const openSourceInHackage = workspace.getConfiguration('haskell').get('openSourceInHackage');
112144
function transform(s: string): string {
113145
return s.replace(
114-
/\[(.+)\]\((file:.+\/doc\/(?:.*html\/libraries\/)?([^\/]+)\/(src\/)?(.+\.html#?.*))\)/gi,
115-
(all, title, localPath, packageName, maybeSrcDir, fileAndAnchor) => {
116-
if (!maybeSrcDir) {
117-
maybeSrcDir = '';
146+
/\[(.+)\]\((file:.+\/doc\/(?:.*html\/libraries\/)?([^\/]+)\/(?:.*\/)?(.+\.html#?.*))\)/gi,
147+
(all, title, localPath, packageName, fileAndAnchor) => {
148+
let hackageUri: string;
149+
if (title == 'Documentation') {
150+
hackageUri = `https://hackage.haskell.org/package/${packageName}/docs/${fileAndAnchor}`;
151+
const encoded = encodeURIComponent(JSON.stringify({ title, localPath, hackageUri }));
152+
let cmd: string;
153+
if (openDocsInHackage) {
154+
cmd = 'command:haskell.openDocumentationOnHackage?' + encoded;
155+
} else {
156+
cmd = 'command:haskell.showDocumentation?' + encoded;
157+
}
158+
return `[${title}](${cmd})`;
159+
} else if (title == 'Source') {
160+
hackageUri = `https://hackage.haskell.org/package/${packageName}/docs/src/${fileAndAnchor.replace(
161+
/-/gi,
162+
'.'
163+
)}`;
164+
const encoded = encodeURIComponent(JSON.stringify({ title, localPath, hackageUri }));
165+
let cmd: string;
166+
if (openSourceInHackage) {
167+
cmd = 'command:haskell.openDocumentationOnHackage?' + encoded;
168+
} else {
169+
cmd = 'command:haskell.showDocumentation?' + encoded;
170+
}
171+
return `[${title}](${cmd})`;
172+
} else {
173+
return s;
118174
}
119-
const hackageUri = `https://hackage.haskell.org/package/${packageName}/docs/${maybeSrcDir}${fileAndAnchor}`;
120-
const encoded = encodeURIComponent(JSON.stringify({ title, localPath, hackageUri }));
121-
const cmd = 'command:haskell.showDocumentation?' + encoded;
122-
return `[${title}](${cmd})`;
123175
}
124176
);
125177
}

0 commit comments

Comments
 (0)