Vscode move to line X after openTextDocument - javascript

I'm developing a VS Code extension that jump to a specific file:num, but I'm stuck at the step of moving the cursor to a specific line after opening a file.
How can I achieve this :
export const openAndMoveToLine = async (file_line: string) => {
// /home/user/some/path.php:10
let [filename, line_number] = file_line.split(":")
// opening the file => OK
let setting: vscode.Uri = vscode.Uri.parse(filename)
let doc = await vscode.workspace.openTextDocument(setting)
vscode.window.showTextDocument(doc, 1, false);
// FIXME: After being opened, now move to the line X => NOK **/
await vscode.commands.executeCommand("cursorMove", {
to: "down", by:'wrappedLine',
value: parseInt(line_number)
});
}
Thank you

It can be done with the TextDocumentShowOptions easily:
const showDocOptions = {
preserveFocus: false,
preview: false,
viewColumn: 1,
// replace with your line_number's
selection: new vscode.Range(314, 0, 314, 0)
};
let doc = await vscode.window.showTextDocument(setting, showDocOptions);

You will first need to get access to the active editor. This is done by adding a .then to the showTextDocument call (which is a Thenable function) that returns a text editor object. You will then be able to use the textEditor variable (as in the example) to set the position of the cursor using the selection property as follows:
vscode.window.showTextDocument(doc, 1, false).then((textEditor: TextEditor) => {
const lineNumber = 1;
const characterNumberOnLine = 1;
const position = new vscode.Position(lineNumber, characterNumberOnLine);
const newSelection = new vscode.Selection(position, position);
textEditor.selection = newSelection;
});
Reference to selection API can be found here.
The usecase that you are exploring has been discussed in GitHub issue that can be found here.

Related

In pdf.js unable to get pdfdocument.annotationStorage to update, and not saving

Based on the examples, and using version 3.3.122 of the library, I am trying to fill out a form, and save the results.
I can see on the viewer.html, that when you update the field, pdfdocument.annotationStorage is updated, but when I attempt it, I can fill out the fields, but the values are not reflected in the annotation storage, and when I save, the values are not coming through.
Yes, I want to use pdf.js library!
` var url = '/test/fw4_2.pdf';
"use strict";
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
// eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
}
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.3.122/pdf.worker.min.js';
// Some PDFs need external cmaps.
//
// const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
const DEFAULT_URL = url;
const PAGE_TO_VIEW = 1;
const SCALE = 1.0;
const ENABLE_XFA = true;
const container = document.getElementById("pageContainer");
const eventBus = new pdfjsViewer.EventBus();
// Loading document.
const loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL,
// cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
enableXfa: ENABLE_XFA,
});
var pdfDocument;
var pdfPage;
var pdfPageView;
var r = (async function () {
pdfDocument = await loadingTask.promise;
// Document loaded, retrieving the page.
pdfPage = await pdfDocument.getPage(PAGE_TO_VIEW);
// Creating the page view with default parameters.
pdfPageView = new pdfjsViewer.PDFPageView({
container,
id: PAGE_TO_VIEW,
scale: SCALE,
defaultViewport: pdfPage.getViewport({ scale: SCALE }),
eventBus,
// We can enable text/annotation/xfa/struct-layers, as needed.
textLayerMode :2,
annotationEditorMode : pdfjsLib.AnnotationEditorType.TextAnnotation,
xfaLayerFactory: pdfDocument.isPureXfa
? new pdfjsViewer.DefaultXfaLayerFactory()
: null,
});
// Associate the actual page with the view, and draw it.
pdfPageView.setPdfPage(pdfPage);
pdfPageView.draw();
})();`
I have tried different so many ways of trying to load the document, saveDocument, getData, and setting annotations directly, with no luck.
I also changed the library versions, and I feel there could be some inconsistencies with the library.

WebDriverIO iterate through URL and scroll through each

I'm using WebDriverIO (v5.18.7) and I'm trying to write something the can go to each URL, and scroll down in increments until you reached the bottom, then move on the next URL. The issue I'm having is when it comes to the scrolling portion of the script, it might scroll once before it goes to the next URL.
From what I'm understanding, the documentation for WebDriverIO says the commands are send in asynchronous, which is handled in the framework behind the scenes. So I tried sticking with the framework and tried browser.execute / browser.executeAsync but wasn't able to get it working.
Here's what I have that seems close to what I want. Any guidance would be appreciated!
const { doesNotMatch } = require('assert');
const assert = require('assert');
const { Driver } = require('selenium-webdriver/chrome');
// variable for list of URLS
const arr = browser.config.urls
describe('Getting URL and scrolling', () => {
it('Get URL and scroll', async () => {
// let i = 0;
for (const value of arr) {
await browser.url(value);
await browser.execute(() => {
const elem = document.querySelector('.info-section');
// scroll until this reaches the end.
// add another for loop with a counter?
elem.scrollIntoView(); //Using this for now as a place holder
});
// i += 1;
}
})
})
Short anwer $('.info-section').scrollIntoView()
See https://webdriver.io/docs/api/element/scrollIntoView.html
WebdriverIO suppors sync and async modes, see https://webdriver.io/docs/sync-vs-async.html

Trying to uderstand Thennables in the VSCode API. Are these equivalent typescript code snippets?

I want to execute a series of edits to a document in the VSCode API. The function that makes it all happen is Workspace.applyEdit which returns a Thennable. This is my first time working with those, and the one being returned by this function is does not work as I expect.
Snippet 1:
import { window, workspace, WorkspaceEdit, Position } from 'vscode';
//doesn't work, only makes first insertion, althouh all info text prints
export function applyEditReprex() {
let text = "\ntest\n";
let target = window.activeTextEditor.document.uri;
let positions = [
new Position(10, 1),
new Position(15, 1),
new Position(20, 1)
];
positions.reduce((applyThennable, position) => {
return (
applyThennable.then(() => {
console.info("Making new edit");
let edit = new WorkspaceEdit();
edit.insert(target, position, text);
workspace.applyEdit(edit);
}))
},
Promise.resolve()
).then(() => {
console.info("Finished edits.");
})
}
Only a single instance of "test" appears in the target document on line 12. The log reports:
Making new edit
Making new edit
Making new edit
Finished edits.
Snippet 2:
My attempt to unroll above into straight chained calls:
import { window, workspace, WorkspaceEdit, Position } from 'vscode';
export function applyEditReprex2() {
let text = "\ntest\n";
let target = window.activeTextEditor.document.uri;
let positions = [
new Position(10, 1),
new Position(15, 1),
new Position(20, 1)
];
console.info("Making new edit");
let edit = new WorkspaceEdit();
edit.insert(target, positions[0], text);
workspace.applyEdit(edit).then(() => {
console.info("Making new edit");
let edit = new WorkspaceEdit();
edit.insert(target, positions[1], text);
workspace.applyEdit(edit).then(() => {
console.info("Making new edit");
let edit = new WorkspaceEdit();
edit.insert(target, positions[2], text);
workspace.applyEdit(edit).then(() => {
console.info("Finished edits.");
})
})
})
}
3 instances of "test" appear in the target file, on lines 12, 17, 22.
The log reports:
Making new edit
Making new edit
Making new edit
Finished edits.
Question
Are there any intricacies of reduce or fat arrow functions that that I may be unaware of that could be causing the first snippet to behave differently from the unrolled version? Or another way: is the unrolled version not equivalent to the reduce in some important way?
You forgot to return the thenable object from the promise's .then() callback, which is essential for promise chaining:
positions.reduce((prevPromise, position) => {
return prevPromise.then(() => {
console.info("Making new edit");
const edit = new WorkspaceEdit();
edit.insert(target, position, text);
const applyThenable = workspace.applyEdit(edit);
return applyThenable;
// ^^^^^^^^^^^^^^^^^^^^
});
}, Promise.resolve())
Btw, my understanding of the API from the documentation you linked is that you should only make a single WorkspaceEdit with multiple insertions:
const positions = [
new Position(10, 1),
new Position(15, 1),
new Position(20, 1)
];
const edit = new WorkspaceEdit();
for (const position in positions) {
edit.insert(target, position, text);
}
workspace.applyEdit(edit).then(() => {
console.info("Finished multi-edit.");
})

Draft.js - convert current block to Atomic Block

I'm working on a custom draft.js plugin that inserts an Atomic Block with a GIF in it. I started by copying the Draft.js Image Plugin as it's almost identical. I've got my plugin working but there's one issue I'm not sure best how to solve.
To insert a GIF I'm following the example addImage Modifier in the Image Plugin. However, this always creates a new Atomic Block after the current selection. If the current block is empty, I want to place the GIF there instead.
Here's what my modifier function looks like:
const addGiphy = (editorState, giphyId) => {
const contentState = editorState.getCurrentContent();
// This creates the new Giphy entity
const contentStateWithEntity = contentState.createEntity("GIPHY", "IMMUTABLE", {
giphyId
});
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
// Work out where the selection is
const currentSelection = editorState.getSelection();
const currentKey = currentSelection.getStartKey();
const currentBlock = editorState.getCurrentContent().getBlockForKey(currentKey);
let newEditorState;
if (currentBlock.getType() === "unstyled" && currentBlock.getText() === "") {
// Current line is empty, we should convert to a gif atomic block
// <INSERT MAGIC HERE>
} else {
// There's stuff here, lets create a new block
newEditorState = AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, " ");
}
return EditorState.forceSelection(
newEditorState,
newEditorState.getCurrentContent().getSelectionAfter()
);
};
I'm not sure how to handle the condition of converting the current block to an Atomic Block. Is this Draft.js best practice? Alternatively, am I better to always insert a new block and then remove the empty block?
For clarity, this same issue also exists in the Image Plugin, it's not something I've introduced.
you can use https://draftjs.org/docs/api-reference-modifier/#setblocktype
const content = Modifier.setBlockType(content, editorState.getSelection(), 'atomic');
const newState = EditorState.push(editorState, content, 'change-block-type');

Is there a way to trigger validation manually in monaco editor?

I'm using the default TypeScript service and the models are initialized asynchronously with one model depending on the other. There's a case where the two models cannot detect each other so it shows a semantic error. If I make some edits in the dependent model, which causes the model to be re-validated, the errors disappear.
I have tried to setModel manually, which solves the problems. However, it destroys the undo history.
Is there a way to re-validate the model manually?
That's my solution, which is extracted from monaco-typescript:
async function revalidateModel(model) {
if (!model || model.isDisposed()) return;
const getWorker = await monaco.languages.typescript.getTypeScriptWorker();
const worker = await getWorker(model.uri);
const diagnostics = (await Promise.all([
worker.getSyntacticDiagnostics(model.uri.toString()),
worker.getSemanticDiagnostics(model.uri.toString())
])).reduce((a, it) => a.concat(it));
const markers = diagnostics.map(d => {
const start = model.getPositionAt(d.start);
const end = model.getPositionAt(d.start + d.length);
return {
severity: monaco.MarkerSeverity.Error,
startLineNumber: start.lineNumber,
startColumn: start.column,
endLineNumber: end.lineNumber,
endColumn: end.column,
message: flattenDiagnosticMessageText(d.messageText, "\n")
};
});
const owner = model.getLanguageIdentifier().language;
monaco.editor.setModelMarkers(model, owner, markers);
}
Call the function above when model is created asynchronizedly.
This is what I did to fix it:
setInterval(() => {
const range = new monaco.Range(1,1,1,1);
const addEmptySpace = {forceMoveMarkers: true, range, text: ' '};
for (const m of monaco.editor.getModels()) {
const toInvert = m.applyEdits([addEmptySpace]);
m.applyEdits(toInvert);
}
}, 50*1000)
Every fifty seconds you insert and immediately remove a space. I don't like it, but it works.

Categories

Resources