Skip to content

RMD Preview fixes#699

Merged
renkun-ken merged 10 commits intoREditorSupport:masterfrom
ElianHugh:rmd-fixes
Jul 14, 2021
Merged

RMD Preview fixes#699
renkun-ken merged 10 commits intoREditorSupport:masterfrom
ElianHugh:rmd-fixes

Conversation

@ElianHugh
Copy link
Copy Markdown
Collaborator

@ElianHugh ElianHugh commented Jul 10, 2021

Implements changes suggested by @ManuelHentschel for R Markdown preview. Should not have any major change in functionality.

Changes:

  • path -> fsPath
  • '/' -> path.sep
  • themeBool -> useDarkTheme
  • command category 'R' -> 'R Markdown'
  • getRPath(false) -> true
  • extDir -> extensionDirectory homeExtDir
  • tmpDir -> temporaryDirectory
  • Handle untitled documents by prompting the user to save the doc prior to rendering
  • Less eager directory creation
  • check exit code rather than error message for knitting errors
  • refresh now re-knits the doc, rather than refreshing the html

Tested on Linux, I don't currently have access to Windows.

Implements changes as suggested by @manuel
Comment thread src/extension.ts Outdated
// global objects used in other files
export const extDir: string = path.join(os.homedir(), '.vscode-R');
export const tmpDir: string = path.join(extDir, 'tmp');
export const extensionDirectory: string = path.join(os.homedir(), '.vscode-R');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both extDir or extensionDirectory are ambiguous because it could mean the installation directory, but I don't come up with a name that makes more sense. Any ideas?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Hmm, what about... localDirectory? homeDirectory?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given it's created in the ~/ directory, I think something relating to 'home' is closer to the right name.

Just throwing ideas out there, because honestly I'm not sure either:

  • homeDir
  • homeExtDir
  • extHomeDir

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like homeExtDir, which is almost the same as its path.

Comment thread src/extension.ts Outdated
export const extDir: string = path.join(os.homedir(), '.vscode-R');
export const tmpDir: string = path.join(extDir, 'tmp');
export const extensionDirectory: string = path.join(os.homedir(), '.vscode-R');
export const temporaryDirectory: string = path.join(extensionDirectory, 'tmp');
Copy link
Copy Markdown
Member

@renkun-ken renkun-ken Jul 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like tmp or temp are already a convention to indicate "temporary" (e.g. os.tmpdir()). Not sure if it really looks better to call it in full.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit ambiguous too, i.e. temporaryDirectory just looks like an alias of os.tmpdir()?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be feasible to simply use os.tmpdir() then (if I recall correctly, there might be issues with user privacy on some platforms)?

And if not, why is this directory declared/created here? It doesn't seem to be used anywhere eles in the code, so wouldn't it be enough to put this in the markdown-preview code?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using os.tmpdir() will have some user privacy problem, unless we create something like /tmp/vscode-R/$USER and make the folder have mode 700.

Just notice that https://github.com/REditorSupport/vscode-R/blob/master/src/helpViewer/helpProvider.ts#L289 uses os.tmpdir() which is probably subject to multi-user clash problem.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should set all references of os.tmpdir (and future references) to temporaryDirectory*?

  • barring issues with the name

Comment thread src/rmarkdown/preview.ts
Comment thread src/rmarkdown/preview.ts Outdated
Comment thread src/rmarkdown/preview.ts Outdated
Comment thread src/extension.ts Outdated
Comment on lines 39 to 45
export async function activate(context: vscode.ExtensionContext): Promise<apiImplementation.RExtensionImplementation> {
if (!fs.existsSync(extDir)) {
fs.mkdirSync(extDir);
if (!fs.existsSync(extensionDirectory)) {
fs.mkdirSync(extensionDirectory);
}

if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir);
if (!fs.existsSync(temporaryDirectory)) {
fs.mkdirSync(temporaryDirectory);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates these directories quite eagerly, i.e. as soon as the extension activates. Wouldn't it be better to create them only if they're actually used?

This could e.g. be implemented by adding a function that creates the directory (if necessary) and then returns its path

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should now only be created when the variable is referred to:

export const extensionDirectory = (): string => util.getDir(path.join(os.homedir(), '.vscode-R'));
export const temporaryDirectory = (): string => util.getDir(path.join(extensionDirectory(), 'tmp'));

Names tbd :)

@ManuelHentschel
Copy link
Copy Markdown
Member

This is working quite nicely now, thanks for the nice work! :)

@renkun-ken
Copy link
Copy Markdown
Member

There seems an inconsistency that the commands are r.markdown.*, global context variables are r.preview.* and the settings are r.rmarkdown.*?

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

Maybe we make it uniform: all under r.markdown?
R.rmarkdown is a bit redundant

@renkun-ken
Copy link
Copy Markdown
Member

renkun-ken commented Jul 11, 2021

Maybe we make it uniform: all under r.markdown?
R.rmarkdown is a bit redundant

I agree. I think if we put a note of breaking changes in the news, and it is okay to rename existing settings of r.rmarkdown.* to r.markdown.*.

@eitsupi
Copy link
Copy Markdown
Contributor

eitsupi commented Jul 11, 2021

Thanks for the great work.
Does the naming convention of the command have anything to do with this issue #472?

@ManuelHentschel
Copy link
Copy Markdown
Member

Maybe we make it uniform: all under r.markdown?
R.rmarkdown is a bit redundant

I agree. I think if we put a note of breaking changes in the news, and it is okay to rename existing settings of r.rmarkdown.* to r.markdown.*.

I wouldn't say r.rmarkdown is redundant. All our settings/commands start with r. since they are contributed by the R extension. Changing the setting names to r.markdown would make it look like they affect .md files rather than .rmd.

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

To me, I think of r.markdown in my head as
"R: Markdown", and r.rmarkdown as "R: R Markdown". However, I get your point re the extension naming scheme

ElianHugh and others added 2 commits July 11, 2021 19:05
- Create dir only when used
- useDarkTheme -> useCodeTheme
- Show warning when attempting to knit an untitled (unsaved) doc
- rename temp and extension directories
Comment thread src/rmarkdown/preview.ts Outdated
- Save untitled file, then retry preview
- refresh button now uses updatePreview rather than refreshPanel
- rename contexts to be more uniform
@renkun-ken
Copy link
Copy Markdown
Member

It looks like the progress only shows when executing the preview command. The refresh does not show up the progress, and thus there is no way to cancel the rendering. I wonder if it makes sense to also show the progress on each refresh?

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

It looks like the progress only shows when executing the preview command. The refresh does not show up the progress, and thus there is no way to cancel the rendering. I wonder if it makes sense to also show the progress on each refresh?

Whoops, yes that should happen. I'll fix that tonight

- Show progress when refreshing a preview
- Save documents prior to knitting
@renkun-ken
Copy link
Copy Markdown
Member

renkun-ken commented Jul 12, 2021

Whenever I save the document, it looks like the document is rendered twice. It is because the file watcher might call multiple times. We might need to remember the file mtime and only call render when the file mtime changes, just like https://github.com/REditorSupport/vscode-R/blob/master/src/session.ts#L550.

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

Seems to be an issue where the uri passed from the file explorer context menu is not equivalent to vscode.window.activeTextEditor.document.uri and causes issues. Not sure why this would be the case, but I guess we could just store uri.path as the key rather than vscode.Uri.

image

@renkun-ken
Copy link
Copy Markdown
Member

Seems to be an issue where the uri passed from the file explorer context menu is not equivalent to vscode.window.activeTextEditor.document.uri and causes issues. Not sure why this would be the case, but I guess we could just store uri.path as the key rather than vscode.Uri.

OK. Using uri.path looks better.

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

ElianHugh commented Jul 13, 2021

Ideally we would keep vscode.Uri so that we still have access to its attributes (e.g. fsPath). However, no matter how I create a uri, an fsPath is not supplied.

// no fsPath
vscode.Uri.parse(fileUri.path);
vscode.Uri.file(fileUri.path);

// no fsPath
const fragment = /([^/\\]+$)/g.exec(fileUri.path)[0];
await vscode.workspace.findFiles(`**/${fragment}`, null, 10)[0]);

// no fsPath
vscode.Uri.from(
            {
                scheme: 'file',
                path: fileUri.path
            }
        );

I have no idea what constitutes the creation of an fsPath.

Will have fix shortly

The vscode.Uri object can lead to problems of equivalence, therefore we'll use a string (fsPath) as an identifier
Comment thread src/rmarkdown/preview.ts Outdated
const fileUri = uri ?? vscode.window.activeTextEditor.document.uri;
const fileName = fileUri.fsPath.substring(fileUri.fsPath.lastIndexOf(path.sep) + 1);
const filePath = uri ? uri.fsPath : vscode.window.activeTextEditor.document.uri.fsPath;
const fileName = filePath.substring(filePath.lastIndexOf(path.sep) + 1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason not to use path.basename()?

Comment thread src/rmarkdown/preview.ts Outdated

public add(uri: vscode.Uri, preview: RMarkdownPreview): Map<vscode.Uri, RMarkdownPreview> {
return this.store.set(uri, preview);
public add(fsPath: string, preview: RMarkdownPreview): Map<string, RMarkdownPreview> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have both filePath and fsPath?

-> Use r.rmarkdown, in line with previous contributions. (probably better left for a later discussion)
-> use consistent name for filePath
-> use path.basename
@renkun-ken
Copy link
Copy Markdown
Member

renkun-ken commented Jul 13, 2021

If the render process exits with an error (e.g. R syntax error in code chunks), the progress will never close.

@ElianHugh
Copy link
Copy Markdown
Collaborator Author

If the render process exits with an error (e.g. R syntax error in code chunks), the progress will never close.

I can't replicate this, this is what should be happening when an error occurs:

EahsGSe8YW

It may be that we expand or change the error detection here:

 childProcess.stderr.on('data', (data: Buffer) => {
                const dat = data.toString('utf8');
                this.rMarkdownOutput.appendLine(dat);
                if (dat.includes('Execution halted')) {
                    reject({ cp: childProcess, wasCancelled: false });
                }
            });

@renkun-ken
Copy link
Copy Markdown
Member

Kapture 2021-07-13 at 20 52 07

Let me take a look at this.

@renkun-ken
Copy link
Copy Markdown
Member

It turns out to be caused by my customized error handling specified in options(error = function(...)) where it does not print "Execution halted" on error but "Exiting on error".

@renkun-ken
Copy link
Copy Markdown
Member

Looks like we should not rely on the error message "Execution halted" (e.g. R in other languages) but the exit code of the process.

@renkun-ken renkun-ken marked this pull request as ready for review July 14, 2021 03:49
Copy link
Copy Markdown
Member

@renkun-ken renkun-ken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Member

@ManuelHentschel ManuelHentschel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works nicely, thanks!

@renkun-ken renkun-ken merged commit 03fcd0f into REditorSupport:master Jul 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants