@@ -13,8 +13,74 @@ import { cleanupSession } from './session';
1313import { config , delay , getRterm , getCurrentWorkspaceFolder } from './util' ;
1414import { rGuestService , isGuestSession } from './liveShare' ;
1515import * as fs from 'fs' ;
16+ import * as yaml from 'js-yaml' ;
17+
1618export let rTerm : vscode . Terminal | undefined = undefined ;
1719
20+ let lastParamsRmdPath : string | undefined ;
21+ let lastParamsRmdVersion : number | undefined ;
22+
23+ const rExprType = new yaml . Type ( '!r' , {
24+ kind : 'scalar' ,
25+ construct : ( data : string ) => ( { __rExpr : data } ) ,
26+ } ) ;
27+ const RMARKDOWN_SCHEMA = yaml . DEFAULT_SCHEMA . extend ( [ rExprType ] ) ;
28+
29+ function valueToR ( val : unknown ) : string {
30+ if ( val === null || val === undefined ) {
31+ return 'NULL' ;
32+ }
33+ if ( typeof val === 'boolean' ) {
34+ return val ? 'TRUE' : 'FALSE' ;
35+ }
36+ if ( typeof val === 'number' ) {
37+ return String ( val ) ;
38+ }
39+ if ( typeof val === 'string' ) {
40+ return `"${ val . replace ( / \\ / g, '\\\\' ) . replace ( / " / g, '\\"' ) } "` ;
41+ }
42+ if ( typeof val === 'object' && val !== null && '__rExpr' in ( val as Record < string , unknown > ) ) {
43+ return ( val as { __rExpr : string } ) . __rExpr ;
44+ }
45+ if ( Array . isArray ( val ) ) {
46+ return `c(${ val . map ( valueToR ) . join ( ', ' ) } )` ;
47+ }
48+ const obj = val as Record < string , unknown > ;
49+ if ( 'value' in obj ) {
50+ return valueToR ( obj [ 'value' ] ) ;
51+ }
52+ const entries = Object . entries ( obj ) . map ( ( [ k , v ] ) => `${ k } = ${ valueToR ( v ) } ` ) ;
53+ return `list(${ entries . join ( ', ' ) } )` ;
54+ }
55+
56+ export function getRmdParamsCommand ( document : vscode . TextDocument ) : string | undefined {
57+ if ( document . languageId !== 'rmd' ) {
58+ return undefined ;
59+ }
60+ const text = document . getText ( ) ;
61+ const match = text . match ( / ^ - - - \s * \n ( [ \s \S ] * ?) \n - - - / ) ;
62+ if ( ! match || ! / ^ \s * p a r a m s \s * : / m. test ( match [ 1 ] ) ) {
63+ return undefined ;
64+ }
65+ const filePath = document . uri . fsPath ;
66+ if ( filePath === lastParamsRmdPath && document . version === lastParamsRmdVersion ) {
67+ return undefined ;
68+ }
69+ lastParamsRmdPath = filePath ;
70+ lastParamsRmdVersion = document . version ;
71+ try {
72+ const frontmatter = yaml . load ( match [ 1 ] , { schema : RMARKDOWN_SCHEMA } ) as Record < string , unknown > ;
73+ const params = frontmatter ?. [ 'params' ] as Record < string , unknown > | undefined ;
74+ if ( ! params || typeof params !== 'object' ) {
75+ return undefined ;
76+ }
77+ const entries = Object . entries ( params ) . map ( ( [ k , v ] ) => `${ k } = ${ valueToR ( v ) } ` ) ;
78+ return `params <- list(${ entries . join ( ', ' ) } )` ;
79+ } catch {
80+ return undefined ;
81+ }
82+ }
83+
1884export async function runSource ( echo : boolean ) : Promise < void > {
1985 const wad = vscode . window . activeTextEditor ?. document ;
2086 if ( ! wad ) {
@@ -234,8 +300,8 @@ export async function runSelectionInTerm(moveCursor: boolean, useRepl = true): P
234300 if ( ! selection ) {
235301 return ;
236302 }
303+ const textEditor = vscode . window . activeTextEditor ;
237304 if ( moveCursor && selection . linesDownToMoveCursor > 0 ) {
238- const textEditor = vscode . window . activeTextEditor ;
239305 if ( ! textEditor ) {
240306 return ;
241307 }
@@ -250,7 +316,8 @@ export async function runSelectionInTerm(moveCursor: boolean, useRepl = true): P
250316 if ( useRepl && vscode . debug . activeDebugSession ?. type === 'R-Debugger' ) {
251317 await sendRangeToRepl ( selection . range ) ;
252318 } else {
253- await runTextInTerm ( selection . selectedText ) ;
319+ const paramsCmd = textEditor ? getRmdParamsCommand ( textEditor . document ) : undefined ;
320+ await runTextInTerm ( paramsCmd ? `${ paramsCmd } \n${ selection . selectedText } ` : selection . selectedText ) ;
254321 }
255322}
256323
@@ -259,12 +326,13 @@ export async function runChunksInTerm(chunks: vscode.Range[]): Promise<void> {
259326 if ( ! textEditor ) {
260327 return ;
261328 }
329+ const paramsCmd = getRmdParamsCommand ( textEditor . document ) ;
262330 const text = chunks
263331 . map ( ( chunk ) => textEditor . document . getText ( chunk ) . trim ( ) )
264332 . filter ( ( chunk ) => chunk . length > 0 )
265333 . join ( '\n' ) ;
266334 if ( text . length > 0 ) {
267- return runTextInTerm ( text ) ;
335+ return runTextInTerm ( paramsCmd ? ` ${ paramsCmd } \n ${ text } ` : text ) ;
268336 }
269337}
270338
0 commit comments