Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions R/session/rstudioapi_util.R
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,7 @@ normalise_pos_or_range_arg <- function(location) {
normalise_text_arg <- function(text, location_length) {
if (length(text) == location_length) {
text
}
else if (length(text) == 1 && location_length > 1) {
} else if (length(text) == 1 && location_length > 1) {
rep(text, location_length)
} else {
stop(
Expand Down
20 changes: 20 additions & 0 deletions html/help/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,24 @@ window.document.body.onload = () => {
};
}
}
// notify vscode when code is clicked:
if (document.body.classList.contains('preClickable')) {
const codeElements = document.getElementsByTagName('pre');
console.log(codeElements);
for (let i = 0; i < codeElements.length; i++) {
const el = codeElements[i];
el.onclick = (me) => {
vscode.postMessage({
message: 'codeClicked',
code: el.textContent || '',
modifiers: {
altKey: me.altKey,
ctrlKey: me.ctrlKey,
shiftKey: me.shiftKey,
metaKey: me.metaKey,
}
});
};
}
}
};
21 changes: 21 additions & 0 deletions html/help/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,26 @@ window.document.body.onload = () => {
};
}
}

// notify vscode when code is clicked:
if(document.body.classList.contains('preClickable')){
const codeElements = document.getElementsByTagName('pre');
console.log(codeElements);
for(let i=0; i<codeElements.length; i++){
const el = codeElements[i];
el.onclick = (me: MouseEvent) => {
vscode.postMessage({
message: 'codeClicked',
code: el.textContent || '',
modifiers: {
altKey: me.altKey,
ctrlKey: me.ctrlKey,
shiftKey: me.shiftKey,
metaKey: me.metaKey,
}
});
};
}
}
};

64 changes: 40 additions & 24 deletions html/help/theme.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
body {
font-size: var(--vscode-editor-font-size);
}

pre, code {
font-family: var(--vscode-editor-font-family);
/* General styling */
body {
font-size: var(--vscode-editor-font-size);
}

Expand All @@ -15,7 +12,6 @@ body table:nth-child(1)[width="100%"] td:nth-child(1){
text-align: right;
}


h1, h2 {
text-align: center;
margin-block-end: 0;
Expand All @@ -29,56 +25,76 @@ a ~ div.header {
display: none;
}

/* Styling for clickable code sections */
pre, code {
font-family: var(--vscode-editor-font-family);
font-size: var(--vscode-editor-font-size);
}

.preClickable pre {
margin: 0px;
padding-top: 0.5em;
padding-bottom: 0.5em;
}

.preHoverPointer .preDiv:hover {
cursor: pointer;
}
.preClickable pre:hover {
background-color: var(--vscode-list-hoverBackground);
}

/* Syntax highlighting in code sections */
.hljs-link {
color: var(--vscode-textLink-foreground)
}

.vscode-light {
--rhelp-number: #cb4b16;
--rhelp-string: #647400;
--rhelp-symbol: #cb4b16;
--rhelp-keyword: #2074b1;
--rhelp-comment: #727e7e;
--rhelp-function: #2074b1;
--rhelp-number: #cb4b16;
--rhelp-string: #647400;
--rhelp-symbol: #cb4b16;
--rhelp-keyword: #2074b1;
--rhelp-comment: #727e7e;
--rhelp-function: #2074b1;
}

.vscode-dark,
.vscode-high-contrast {
--rhelp-number: #b5cea8;
--rhelp-string: #CE9178;
--rhelp-symbol: #4EC9B0;
--rhelp-keyword: #569cd6;
--rhelp-comment: #6A9955;
--rhelp-function: #DCDCAA;
--rhelp-number: #b5cea8;
--rhelp-string: #CE9178;
--rhelp-symbol: #4EC9B0;
--rhelp-keyword: #569cd6;
--rhelp-comment: #6A9955;
--rhelp-function: #DCDCAA;
}

.hljs-number {
color: var(--rhelp-number)
color: var(--rhelp-number)
}

.hljs-regexp,
.hljs-bullet,
.hljs-string {
color: var(--rhelp-string)
color: var(--rhelp-string)
}

.hljs-symbol,
.hljs-class {
color: var(--rhelp-symbol)
color: var(--rhelp-symbol)
}

.hljs-literal,
.hljs-keyword {
color: var(--rhelp-keyword)
color: var(--rhelp-keyword)
}

.hljs-built_in,
.hljs-function {
color: var(--rhelp-function)
color: var(--rhelp-function)
}

.hljs-quote,
.hljs-comment {
color: var(--rhelp-comment)
color: var(--rhelp-comment)
}

12 changes: 11 additions & 1 deletion html/help/webviewMessages.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ interface LinkClickedMessage extends IOutMessage {
href: string,
scrollY: number
}
interface CodeClickedMessage extends IOutMessage {
message: 'codeClicked',
code: string,
modifiers: {
altKey: boolean,
ctrlKey: boolean,
shiftKey: boolean,
metaKey: boolean,
}
}

type OutMessage = LogMessage | MouseClickMessage | LinkClickedMessage;
type OutMessage = LogMessage | MouseClickMessage | LinkClickedMessage | CodeClickedMessage;

55 changes: 55 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,60 @@
"default": true,
"markdownDescription": "Show links to matching help pages in hover"
},
"r.helpPanel.clickCodeExamples": {
"type": "object",
"markdownDescription": "What happens when clicking code examples on help pages. Might require restarting to take effect.",
"default": {
"Click": "Copy",
"Ctrl+Click": "Run",
"Shift+Click": "Ignore"
},
"properties": {
"Click": {
"type": "string",
"default": "Copy",
"enum": [
"Ignore",
"Copy",
"Run"
],
"enumDescriptions": [
"Do nothing",
"Copy the code to the clipboard",
"Run the code in the terminal"
]
},
"Ctrl+Click": {
"type": "string",
"default": "Run",
"enum": [
"Ignore",
"Copy",
"Run"
],
"enumDescriptions": [
"Do nothing",
"Copy the code to the clipboard",
"Run the code in the terminal"
]
},
"Shift+Click": {
"type": "string",
"default": "Ignore",
"enum": [
"Ignore",
"Copy",
"Run"
],
"enumDescriptions": [
"Do nothing",
"Copy the code to the clipboard",
"Run the code in the terminal"
]
}
},
"additionalProperties": false
},
"r.source.encoding": {
"type": "string",
"default": "UTF-8",
Expand Down Expand Up @@ -1825,6 +1879,7 @@
"vscode:prepublish": "tsc -p . && tsc -p ./html/help && tsc -p ./html/httpgd",
"compile": "tsc -p . && tsc -p ./html/help && tsc -p ./html/httpgd",
"watch": "tsc -p . --watch",
"watchHelp": "tsc -p ./html/help --watch",
"pretest": "tsc -p ./",
"test": "node ./out/test/runTest.js",
"lint": "eslint src --ext ts"
Expand Down
25 changes: 25 additions & 0 deletions src/helpViewer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import {HelpTreeWrapper} from './treeView';
import {PackageManager} from './packages';
import {isGuestSession, rGuestService} from '../liveShare';

export type CodeClickAction = 'Ignore' | 'Copy' | 'Run';
export interface CodeClickConfig {
'Click': CodeClickAction,
'Ctrl+Click': CodeClickAction,
'Shift+Click': CodeClickAction,
}
const CODE_CLICKS: (keyof CodeClickConfig)[] = ['Click', 'Ctrl+Click', 'Shift+Click'];

// Initialization function that is called once when activating the extension
export async function initializeHelp(
context: vscode.ExtensionContext,
Expand Down Expand Up @@ -563,6 +571,23 @@ function pimpMyHelp(helpFile: HelpFile): HelpFile {

// Remove style elements specified in the html itself (replaced with custom CSS)
$('head style').remove();

// Split code examples at empty lines:
const codeClickConfig = config().get<CodeClickConfig>('helpPanel.clickCodeExamples');
const isEnabled = CODE_CLICKS.some(k => codeClickConfig[k] !== 'Ignore');
if(isEnabled){
$('body').addClass('preClickable');
const codeSections = $('pre');
codeSections.each((i, section) => {
const innerHtml = $(section).html();
const newPres = innerHtml.split('\n\n').map(s => `<pre>${s}</pre>`);
const newHtml = '<div class="preDiv">' + newPres.join('\n') + '</div>';
$(section).replaceWith(newHtml);
});
}
if(codeClickConfig.Click !== 'Ignore'){
$('body').addClass('preHoverPointer');
}

// Apply syntax highlighting:
if (config().get<boolean>('helpPanel.enableSyntaxHighlighting')) {
Expand Down
57 changes: 43 additions & 14 deletions src/helpViewer/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import * as vscode from 'vscode';
import * as cheerio from 'cheerio';

import { HelpFile, RHelp } from '.';
import { CodeClickConfig, HelpFile, RHelp } from '.';
import { setContext, UriIcon, config } from '../util';
import { runTextInTerm } from '../rTerminal';
import { OutMessage } from './webviewMessages';

//// Declaration of interfaces used/implemented by the Help Panel class
// specified when creating a new help panel
Expand Down Expand Up @@ -102,7 +104,7 @@ export class HelpPanel {
});

// sent by javascript added to the help pages, e.g. when a link or mouse button is clicked
this.panel.webview.onDidReceiveMessage((e: {[key: string]: any}) => {
this.panel.webview.onDidReceiveMessage((e: OutMessage) => {
void this.handleMessage(e);
});

Expand Down Expand Up @@ -209,11 +211,11 @@ export class HelpPanel {
}

// handle message produced by javascript inside the help page
private async handleMessage(msg: {[key: string]: any}){
if('message' in msg && msg.message === 'linkClicked'){
private async handleMessage(msg: OutMessage){
if(msg.message === 'linkClicked'){
// handle hyperlinks clicked in the webview
// normal navigation does not work in webviews (even on localhost)
const href: string = <string>msg.href || '';
const href: string = msg.href || '';
const currentScrollY: number = Number(msg.scrollY) || 0;
console.log('Link clicked: ' + href);

Expand Down Expand Up @@ -261,9 +263,36 @@ export class HelpPanel {
} else if(button === 4){
this._goForward(currentScrollY);
}
} else if(msg.message === 'text'){
// used for logging/debugging
console.log(`Message (text): ${String(msg.text)}`);
} else if(msg.message === 'codeClicked') {
if(!msg.code){
return;
}
// Process modifiers:
const isCtrlClick = msg.modifiers.ctrlKey || msg.modifiers.metaKey;
const isShiftClick = msg.modifiers.shiftKey;
const isNormalClick = !isCtrlClick && !isShiftClick;

// Check wheter to copy or run the code (or both or none)
const codeClickConfig = config().get<CodeClickConfig>('helpPanel.clickCodeExamples');
const runCode = (
isCtrlClick && codeClickConfig['Ctrl+Click'] === 'Run'
|| isShiftClick && codeClickConfig['Shift+Click'] === 'Run'
|| isNormalClick && codeClickConfig['Click'] === 'Run'
);
const copyCode = (
isCtrlClick && codeClickConfig['Ctrl+Click'] === 'Copy'
|| isShiftClick && codeClickConfig['Shift+Click'] === 'Copy'
|| isNormalClick && codeClickConfig['Click'] === 'Copy'
);

// Execute action:
if(copyCode){
void vscode.env.clipboard.writeText(msg.code);
void vscode.window.showInformationMessage('Copied code example to clipboard.');
}
if(runCode){
void runTextInTerm(msg.code);
}
} else{
console.log('Unknown message:', msg);
}
Expand All @@ -283,12 +312,12 @@ export class HelpPanel {
$('body').attr('relpath', relPath);
$('body').attr('scrollyto', `${helpFile.scrollY ?? -1}`);

if(styleUri){
$('body').append(`\n<link rel="stylesheet" href="${styleUri.toString()}"></link>`);
}
if(scriptUri){
$('body').append(`\n<script src=${scriptUri.toString()}></script>`);
}
if(styleUri){
$('body').append(`\n<link rel="stylesheet" href="${styleUri.toString()}"></link>`);
}
if(scriptUri){
$('body').append(`\n<script src=${scriptUri.toString()}></script>`);
}


// convert to string
Expand Down
Loading