-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add templates.R * Implement newDraft command * Fix path * Update draft * Fix file path * Remove unused eslint-disable * Disable eslint no-explicit-any * Handle create_dir * Create untitled document if not create_dir * Use spawn * Update getTemplateItems * Format file * Update getTemplateItems * Update confirm replacing folder
- Loading branch information
1 parent
9b525aa
commit f5d857e
Showing
6 changed files
with
184 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
requireNamespace("jsonlite") | ||
requireNamespace("yaml") | ||
|
||
pkgs <- .packages(all.available = TRUE) | ||
templates <- new.env() | ||
template_dirs <- lapply(pkgs, function(pkg) { | ||
dir <- system.file("rmarkdown/templates", package = pkg) | ||
if (dir.exists(dir)) { | ||
ids <- list.dirs(dir, full.names = FALSE, recursive = FALSE) | ||
for (id in ids) { | ||
file <- file.path(dir, id, "template.yaml") | ||
if (file.exists(file)) { | ||
data <- yaml::read_yaml(file) | ||
data$id <- id | ||
data$package <- pkg | ||
templates[[paste0(pkg, "::", id)]] <- data | ||
} | ||
} | ||
} | ||
}) | ||
|
||
template_list <- unname(as.list(templates)) | ||
lim <- Sys.getenv("VSCR_LIM") | ||
json <- jsonlite::toJSON(template_list, auto_unbox = TRUE) | ||
cat(lim, json, lim, sep = "\n", file = stdout()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { QuickPickItem, QuickPickOptions, Uri, window, workspace } from 'vscode'; | ||
import { extensionContext } from '../extension'; | ||
import { executeRCommand, getCurrentWorkspaceFolder, getRpath, ToRStringLiteral, spawnAsync, getConfirmation } from '../util'; | ||
import * as cp from 'child_process'; | ||
import * as path from 'path'; | ||
import * as fs from 'fs'; | ||
import * as os from 'os'; | ||
|
||
interface TemplateInfo { | ||
id: string; | ||
package: string; | ||
name: string; | ||
description: string; | ||
create_dir: boolean; | ||
} | ||
|
||
interface TemplateItem extends QuickPickItem { | ||
info: TemplateInfo; | ||
} | ||
|
||
async function getTemplateItems(cwd: string): Promise<TemplateItem[]> { | ||
const lim = '---vsc---'; | ||
const rPath = await getRpath(); | ||
const options: cp.CommonOptions = { | ||
cwd: cwd, | ||
env: { | ||
...process.env, | ||
VSCR_LIM: lim | ||
} | ||
}; | ||
|
||
const rScriptFile = extensionContext.asAbsolutePath('R/rmarkdown/templates.R'); | ||
const args = [ | ||
'--silent', | ||
'--slave', | ||
'--no-save', | ||
'--no-restore', | ||
'-f', | ||
rScriptFile | ||
]; | ||
|
||
try { | ||
const result = await spawnAsync(rPath, args, options); | ||
if (result.status !== 0) { | ||
throw result.error || new Error(result.stderr); | ||
} | ||
const re = new RegExp(`${lim}(.*)${lim}`, 'ms'); | ||
const match = re.exec(result.stdout); | ||
if (match.length !== 2) { | ||
throw new Error('Could not parse R output.'); | ||
} | ||
const json = match[1]; | ||
const templates = <TemplateInfo[]>JSON.parse(json) || []; | ||
const items = templates.map((x) => { | ||
return { | ||
alwaysShow: false, | ||
description: `{${x.package}}`, | ||
label: x.name + (x.create_dir ? ' $(new-folder)' : ''), | ||
detail: x.description, | ||
picked: false, | ||
info: x | ||
}; | ||
}); | ||
return items; | ||
} catch (e) { | ||
console.log(e); | ||
void window.showErrorMessage((<{ message: string }>e).message); | ||
} | ||
} | ||
|
||
async function launchTemplatePicker(cwd: string): Promise<TemplateItem> { | ||
const options: QuickPickOptions = { | ||
matchOnDescription: true, | ||
matchOnDetail: true, | ||
canPickMany: false, | ||
ignoreFocusOut: false, | ||
placeHolder: '', | ||
onDidSelectItem: undefined | ||
}; | ||
|
||
const items = await getTemplateItems(cwd); | ||
|
||
const selection: TemplateItem = await window.showQuickPick<TemplateItem>(items, options); | ||
return selection; | ||
} | ||
|
||
async function makeDraft(file: string, template: TemplateItem, cwd: string): Promise<string> { | ||
const fileString = ToRStringLiteral(file, ''); | ||
const cmd = `cat(normalizePath(rmarkdown::draft(file='${fileString}', template='${template.info.id}', package='${template.info.package}', edit=FALSE)))`; | ||
return await executeRCommand(cmd, cwd, (e: Error) => { | ||
void window.showErrorMessage(e.message); | ||
return ''; | ||
}); | ||
} | ||
|
||
export async function newDraft(): Promise<void> { | ||
const cwd = getCurrentWorkspaceFolder()?.uri.fsPath ?? os.homedir(); | ||
const template = await launchTemplatePicker(cwd); | ||
if (!template) { | ||
return; | ||
} | ||
|
||
if (template.info.create_dir) { | ||
let defaultPath = path.join(cwd, 'draft'); | ||
let i = 1; | ||
while (fs.existsSync(defaultPath)) { | ||
defaultPath = path.join(cwd, `draft_${++i}`); | ||
} | ||
const uri = await window.showSaveDialog({ | ||
defaultUri: Uri.file(defaultPath), | ||
filters: { | ||
'Folder': [''] | ||
}, | ||
saveLabel: 'Create Folder', | ||
title: 'R Markdown: New Draft' | ||
}); | ||
|
||
if (uri) { | ||
const parsedPath = path.parse(uri.fsPath); | ||
const dir = path.join(parsedPath.dir, parsedPath.name); | ||
if (fs.existsSync(dir)) { | ||
if (await getConfirmation(`Folder already exists. Are you sure to replace the folder?`)) { | ||
fs.rmdirSync(dir, { recursive: true }); | ||
} else { | ||
return; | ||
} | ||
} | ||
|
||
const draftPath = await makeDraft(uri.fsPath, template, cwd); | ||
if (draftPath) { | ||
await workspace.openTextDocument(draftPath) | ||
.then(document => window.showTextDocument(document)); | ||
} | ||
} | ||
} else { | ||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vscode-R-')); | ||
const tempFile = path.join(tempDir, 'draft.Rmd'); | ||
const draftPath = await makeDraft(tempFile, template, cwd); | ||
if (draftPath) { | ||
const text = fs.readFileSync(draftPath, 'utf8'); | ||
await workspace.openTextDocument({ language: 'rmd', content: text }) | ||
.then(document => window.showTextDocument(document)); | ||
} | ||
fs.rmdirSync(tempDir, { recursive: true }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters