Add different number of spaces to multiple lines so that each line has equal amount of characters - visual-studio-code

Is there an easy way to add spaces to multiple lines so that each line has equal amount of characters?
Motivation, say I want to add '*' at end of each line
/***************************
* This is line 1. *
* Line2. *
* May be line3. *
* For sure this is line 4. *
****************************/
Without using any custom format program, is there a way in VS code to add different number of spaces just before the last '*' like so:
/***************************
* This is line 1. *
* Line2 *
* May be line3 *
* For sure this is line 4. *
****************************/

select all the * at the lines that are incorrect
add as much spaces as needed to get all *'s beyond the correct position
Esc to get out of multi cursor
Place Multi Cursor on all lines at the position where you want the *'s
press Ctrl+Delete
Esc to get out of multi cursor

You can do this fairly simply with an extension I wrote, Find and Transform, because it allows you to use javascript or the vscode extension api in a replacement. So starting with this text:
/***************************
* This is line 1.
* Line2.
* May be line3.
* For sure this is line 4.
****************************/
you would make this keybinding (in your keybindings.json):
{
"key": "alt+q", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"replace": [
"$${",
"const str = `${selectedText}`;", // get the selected text
// since the selected text can contain newlines, surround the variable with backticks
"let lineArray = str.split('\\n');", // newlines must be double-escaped
"let firstLineLength = lineArray[0].length;",
"lineArray = lineArray.map((line, index) => {",
"if (index === 0) return line;",
"else if (line === lineArray.at(lineArray.length-1)) return line;",
"else return `${line.padEnd(firstLineLength-1, ' ')}*`;",
"});",
"return lineArray.join('\\n');",
"}$$"
]
}
}
So the replacement is straightforward javascript which gets the selected text, splits it on the newlines and then uses the length of the first line to pad the other lines with spaces and then adds a * to the end of each line. It does nothing to the first or last line of the selection.
Demo:
You can do multiple selections at a time too.

Related

Formating Visual Studio Column Jump

I'd like to edit my Visual Studio Code.
When I write my symbols on my keyboard to VSC, they'll get written Column by Column on the current Row.
\ Line of Code + Column.
(Ln , Col )
Extensions: "Select By"
= to jump to a certain column.
However, when i like to jump to 'column 50', it will only jump to the >End of Line.
// Example
// Goal is to get a Hotkey to Jump to Column 50
// Activated Hotkey*
cout << "Hello World:" << endl; // If i use my Hotkey i get to the Column 30, not 50. Picture is enhanced*
/* The end of line is here: 30. */
Question: How can I achieve my Jump
via the given Extension? (Any easy solution would be helpful).
I don't like to use the Ln, Col in Vsc, because clicking on the UI is for me over the time to slow.
I'd like to use f.e. Cmd + M to get to my "middle", So for me column 50.
Hence, i don't like to go to Middle of my current Screenformat.
Additional prefered Question: One way how i like to solve the issue is in C64 Style.
Is there any way to fill out the Visual Studio Code Screen by empty chars?
So as an Preset.
I know, that i can just copy & Paste. Or write an empty script. But that doesn't seem convenient inside the Configuration. I tryed to find that now unsucessfully since 2 weeks..
The reason is for me, that i currently try to code more cleaner.
And to achieve that (I have read many Clean Code Books during school and Github), i just like to try this time an historical approach by setting my own column points/ marks. (Basic C64-menu wise)
Thank you in advance!
Sincerely
Edit: I have enhanced beforehand.
Edit2: I have tryed the Find and Transform Extension pointed by Mark. Thank you for your time!
When i press the given Hotkey, It does marks the previous chars. but it doesn't start at column 50.
It marks at end of line.
I only like to move the cursor to column 50 and surpress the end of line.
does this key binding work
{
"key": "ctrl+i ctrl+m", // or any other key binding
"when": "editorTextFocus",
"command": "moveby.calculation",
"args": {
"charNrEx": "50"
}
}
Or use Ctrl+G and type lineNr:charNr
At the risk of not fully understanding the question, if what you want to do is pad any line to the 50th column with spaces, you can try this approach.
Install the extension Find and Transform
Make this keybinding (or it could be a command):
{
"key": "alt+q", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
// this will select the current line, cursor can start anywhere on line
"preCommands": ["cursorEnd", "cursorHomeSelect", "cursorHomeSelect"],
"replace": [
"$${",
"const str = `${TM_CURRENT_LINE}`;",
"let currentLength = str.length;", // current line length
"if (currentLength >= 49) return str;", // do nothing
// pad to whatever column you want
"else return `${str.padEnd(49, ' ')}`;", // pad with spaces
"}$$"
],
"restrictFind": "line", // only on lines with a cursor
"postCommands": ["cursorRight"] // just cancels the selection
}
}
It'll work on multiple lines too if each line has a cursor on it

Is it possible to have a snippet that considers the length of my input?

I would like to define a snippet for comments like
//************
//* foo A1 *
//************
where I enter foo A1 and it would create a line with (6+ len(${1}) asterisks etc. - is that doable and if so, how?
While I am a big proponent of HyperSnips (see
[VSCODE]: Is there a way to insert N times the same characters,
VS Code: how to make a python snippet that after string or expression hitting tab will transform it and
VSCode Advanced Custom Snippets for how to use it),
it is instructive to see how to do this with just the built-in snippet functionality in vscode. Here is a snippet that does what you want:
"Custom Comment": {
"prefix": ["cc2"], // whatever trigger you want, then tab, write your info and tab again
"body": [
"//***${1/./*/g}***",
"//* $1 *",
"//***${1/./*/g}***"
]
},
That just adds 3 asterisks to the beginning and 3 to the end of your added comment, each character of which is replaced by an asterisk as well.
You can use the extension HyperSnips
snippet comment "Comment" A
``rv = '//' + '*'.repeat(t[0].length + 6)``
//* $1 *
``rv = '//' + '*'.repeat(t[0].length + 6)``
endsnippet

VSCode: Extension: folding section based on first blank line found or to the start of the next similar section

How can I make a VSCode extension folding strategy based on the first blank line following a starting folding marker?
## Some section --|
Any text... | (this should fold)
...more text. --|
(blank line)
## Another section (next fold...)
I've tried lots of regex in the language-configuration.json.
"folding": {
"markers": {
"start": "^##",
"end": "^\\s*$"
} },
If I change things to test with something other than a blank (or whitespace) line as the end delimiter it works. Can't use the next start marker to mark the end of the last or it includes it in the fold (I tried look ahead regex, but I think the regex are applied line by line and the matches can't span lines?)
It's similar to the folding needed for Markdown which VSCode handles well (don't know if that's using a more complex method like https://code.visualstudio.com/api/references/vscode-api#FoldingRangeProvider).
Maybe something in the fixes for [folding] should not fold white space after function has something to do with it.
What I learned: 1. the begin and end regex are applied line by line. 2. tmLanguage start/end regex will work on blank lines, but currently language-configuration folding doesn't seem to work on blank lines.
And since blank lines are in this case a hack for ending at the next begin section:
To solve the problem of folding a section to the next similar section I used the FoldingRangeProvider.
disposable = vscode.languages.registerFoldingRangeProvider('myExt', {
provideFoldingRanges(document, context, token) {
//console.log('folding range invoked'); // comes here on every character edit
let sectionStart = 0, FR = [], re = /^## /; // regex to detect start of region
for (let i = 0; i < document.lineCount; i++) {
if (re.test(document.lineAt(i).text)) {
if (sectionStart > 0) {
FR.push(new vscode.FoldingRange(sectionStart, i - 1, vscode.FoldingRangeKind.Region));
}
sectionStart = i;
}
}
if (sectionStart > 0) { FR.push(new vscode.FoldingRange(sectionStart, document.lineCount - 1, vscode.FoldingRangeKind.Region)); }
return FR;
}
});
Set "editor.foldingStrategy": "auto". You can make it more sophisticated to preserve white space between sections.

iText PDFSweep RegexBasedCleanupStrategy not work in some case

I'm trying to use iText PDFSweep RegexBasedCleanupStrategy to redact some words from pdf, however I only want to redact the word but not appear in other word, eg.
I want to redact "al" as single word, but I don't want to redact the "al" in "mineral".
So I add the word boundary("\b") in the Regex as parameter to RegexBasedCleanupStrategy,
new RegexBasedCleanupStrategy("\\bal\\b")
however the pdfAutoSweep.cleanUp not work if the word is at the end of line.
In short
The cause of this issue is that the routine that flattens the extracted text chunks into a single String for applying the regular expression does not insert any indicator for a line break. Thus, in that String the last letter from one line is immediately followed by the first letter of the next which hides the word boundary. One can fix the behavior by adding an appropriate character to the String in case of a line break.
The problematic code
The routine that flattens the extracted text chunks into a single String is CharacterRenderInfo.mapString(List<CharacterRenderInfo>) in the package com.itextpdf.kernel.pdf.canvas.parser.listener. In case of a merely horizontal gap this routine inserts a space character but in case of a vertical offset, i.e. a line break, it adds nothing extra to the StringBuilder in which the String representation is generated:
if (chunk.sameLine(lastChunk)) {
// we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
if (chunk.getLocation().isAtWordBoundary(lastChunk.getLocation()) && !chunk.getText().startsWith(" ") && !chunk.getText().endsWith(" ")) {
sb.append(' ');
}
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
} else {
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
}
A possible fix
One can extend the code above to insert a newline character in case of a line break:
if (chunk.sameLine(lastChunk)) {
// we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
if (chunk.getLocation().isAtWordBoundary(lastChunk.getLocation()) && !chunk.getText().startsWith(" ") && !chunk.getText().endsWith(" ")) {
sb.append(' ');
}
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
} else {
sb.append('\n');
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
}
This CharacterRenderInfo.mapString method is only called from the RegexBasedLocationExtractionStrategy method getResultantLocations() (package com.itextpdf.kernel.pdf.canvas.parser.listener), and only for the task mentioned, i.e. applying the regular expression in question. Thus, enabling it to properly allow recognition of word boundaries should not break anything but indeed should be considered a fix.
One merely might consider adding a different character for a line break, e.g. a plain space ' ' if one does not want to treat vertical gaps any different than horizontal ones. For a general fix one might, therefore, consider making this character a settable property of the strategy.
Versions
I tested with iText 7.1.4-SNAPSHOT and PDFSweep 2.0.3-SNAPSHOT.

haxe: get line number and line position from haxe.macro.Position

In haxe macro for every expression we can get it's position in form of http://api.haxe.org/haxe/macro/Position.html :
{
file:String, // filename - relative to source path
min:Int, // position of first character in file
max:Int // position of last character in file
}
I want to get line number and position in line for min and max variables.
I definitely can do this by opening the file
FileSystem.absolutePath(Context.resolvePath(posInfo.file));
and calculating line number, but haxe already does this, it's much better to get this info from compiler. Is it possible?
In the current versions of Haxe you can use PositionTools.toLocation
class Macro {
public static macro function log(args:Array<Expr>):Expr {
var loc = PositionTools.toLocation(Context.currentPos());
var locStr = loc.file + ":" + loc.range.start.line;
args.unshift(macro $v{locStr});
return macro SomeExtern.logFunc($a{args});
}
}
to have Macro.log("hi!") translate into SomeExtern.logFunc("Main:5", "hi!")
I know a few projects do that manually (like checkstyle)
Load the file content, find the carriage returns (\n, \r or \n\r) mark the character position for each new line, lookup your pos.min against those positions
I guess it might be more problematic if you have multibyte characters in the file ...
In haxe 4 PositionTools.toLocation function was added.