How can I add an end-of-line comment using Roslyn - roslyn

I want to add a comment to the end of a line using Roslyn.
Potentially, I want to add a comment to multiple lines in the same operation, so I would like to work with a DocumentEditor or with a SyntaxRewriter (CSharpSyntaxRewriter or VisualBasicSyntaxRewriter).
Using a DocumentEditor I am able to find the EndOfLineTrivia where I want to insert the comment, but I don't know how to insert the SingleLineCommentTrivia before it.
Is there any way to insert SingleLineCommentTrivia using a DocumentEditor?
Using a SyntaxRewriter, I can override the VisitTrivia method and find the EndOfLineTrivia where I want to insert the comment. I can replace the EndOfLineTrivia with SingleLineCommentTrivia, but then the line break is lost.
Is there any way that I can replace EndOfLineTrivia with a sequence of SingleLineCommentTrivia and EndOfLineTrivia using a SyntaxRewriter?
If neither of these methods is possible, what would be a better way to insert an end-of-line comment?

I think that I have found answers for both cases:
Using a DocumentEditor you can replace a SyntaxNode, but not a SyntaxTrivia.
However all trivia is associated with a SyntaxNode. What you have to do is to locate that SyntaxNode, create a copy of it with modified trivia and then replace the SytnaxNode.
Using SyntaxNode.WithTrailingTrivia(), you can replace the existing trailing trivia with one or more SyntaxTrivia objects.
Without going into every detail, the code is roughly:
SyntaxNode OldNode ;
DocumentEditor RoslynEditor ;
// Initialize OldNode and RoslynEditor ...
var st = SyntaxFactory.Comment ( " // my comment" ) ;
var NewNode = p.WithTrailingTrivia ( st, SyntaxFactory.CarriageReturnLineFeed ) ;
RoslynEditor.ReplaceNode ( p, NewNode ) ;
// and later ...
Dim newRoot = RoslynEditor.GetChangedRoot() ;
Note: This assumes that the end-of-line where the comment should be inserted, is the in the trailing trivia of the SyntaxNode, where it will be replaced. If not, then a new line break will be inserted.
Using a SyntaxRewriter, the trick is to use SyntaxFactory.EndOfLine, to generate a SyntaxToken containing both the end-of-line comment and the actual end of line.
Without showing the details of how to select which line to modify, this is the approximate logic:
class MLHideRewriterCS : CSharpSyntaxRewriter
{
...
public override SyntaxTrivia VisitTrivia ( SyntaxTrivia trivia )
{
// Some logic to detect the correct line ...
if ( this is the line that we want to modify )
{
var expression = SyntaxFactory.EndOfLine ( " // my comment" ) ;
return expression ;
}
return base.VisitTrivia ( trivia ) ;
}
}

Related

Split string and get values before different delimiters

Given the code:
procedure example {
x=3;
y = z +c ;
while p {
b = a+c ;
}
}
I would like to split the code by using the delimiters {, ;, and }.
After splitting, I would like to get the information before it together with the delimiter.
So for example, I would like to get procedure example {, x=3;, y=z+c;, }. Then I would like to push it into a list<pair<int, string>> sList. Could someone explain how this can be done in c++?
I tried following this example: Parse (split) a string in C++ using string delimiter (standard C++), but I could only get one token. I want the entire line. I am new to c++, and the list, splitting, etc. is confusing.
Edit: So I have implemented it, and this is the code:
size_t openCurlyBracket = lines.find("{");
size_t closeCurlyBracket = lines.find("}");
size_t semiColon = lines.find(";");
if (semiColon != string::npos) {
cout << lines.substr(0, semiColon + 1) + "\n";
}
However, it seems that it can't separate based on semicolon separately, openBracket and closeBracket. Anyone knows how to separate based on these characters individually?
2nd Edit:
I have done this (codes below). It is separating correctly, I have one for open curly bracket. I was planning on adding the value to the list in the commented area below. However, when i think about it, if i do that, then the order of information in the list will be messed up. As i have another while loop which separates based on open curly bracket. Any idea on how i can add the information in an order?
Example:
1. procedure example {
2. x=3;
3. y = z+c
4. while p{
and so on.
while (semiColon != string::npos) {
semiColon++;
//add list here
semiColon = lines.find(';',semiColon);
}
I think that you should read about std::string::find_first_of function.
Searches the string for the first character that matches any of the characters specified in its arguments.
I have a problem to understand what you really want to achieve. Let's say this is an example of the find_first_of function use.
list<string> split(string lines)
{
list<string> result;
size_t position = 0;
while((position = lines.find_first_of("{};\n")) != string::npos)
{
if(lines[position] != '\n')
{
result.push_back(lines.substr(0, position+1));
}
lines = lines.substr(position+1);
}
return result;
}

Notepad++ or UltraEdit: regex remove special duplicates

I need to remove duplicates if
key = anything
but NOT
key=anything
the key can be anything too
e.g.
edit_home=home must be in place
while
edit_home = home or even other string must be removed IF edit_home is a duplicate
for all the lines of the document
thank you
p.s. clearer example:
one=you are
two=we are
three_why=8908908
one = good
two = fine
three_4 = best
three_why = win
from that list i only need to keep:
one=you are
two=we are
three_why=8908908
three_4 = best // because three_4 doesn't have a duplicate
I found a method to do it, but I would need a better search list support by regex or a plugin or a direct regex (which I don't know).
That is: I have two files to compare.
One has the full keys, the other has incomplete.
I merge in a new file all the keys from the first file with those ones of the second, in groups (because the keys are in groups e.g. many keys titled one, many titled two and so on...). Then I regex replace all the keys in the new file by
find (.*)(\s\=\s) replace with \1\=
So they all become key=anything
Then I replace everything after = with empty to isolate the keys.
Then remove the duplicates.
At this point I have trouble to do something like
^.*(^keyone\b|^keytwo\b|^keythree\b).*$
to find all those keys in the document I need. So from that I can select all and replace with the correct keys.
Why? Because in this example the keys are 3 only BUT indeed the keys are many and the find field breaks at a certain point.
How to do it right?
Update: I found Toolbucket plugin which allows to search for many strings, but another issue is that in addition to duplicate, I also have to remove the original.
That is, if I find 2 times the same key "one" I have to remove all the lines containing one.
Ctrl + F
Find tab
Find what: ^.*\S=\S.*$
Find All in Current Document
Copy result from result window to a new window (the list of Line 1: Line 2: Line 3: ...)
Ctrl + F
Replace tab
(the following will remove the leading "Line number:" from every line)
Find what: ^.*?\d:\s
Replace with: Empty
ok, after all that i wrote, one solution could be (therefore, once i have the merged keys)
(?m)^(.*)$(?=\r?\n^(?!\1).*(?s).*?\1)
with this i can mark/highlight all the duplicated keys :-) so then i can manage those only, removing them from the first list and adding what remains to the second file...
If someone has a solution with a direct regex will be really appreciated
Here is a commented UltraEdit script for this task.
// Note: This script does not work for large files as it loads the
// entire file content into very limited scripting memory for fast
// processing even with multiple GB of RAM installed.
if (UltraEdit.document.length > 0) // Is any file opened?
{
// Define environment for this script and select entire file content.
UltraEdit.insertMode();
UltraEdit.columnModeOff();
UltraEdit.activeDocument.selectAll();
// Determine line termination used currently in active file.
var sLineTerm = "\r\n";
if (typeof(UltraEdit.activeDocument.lineTerminator) == "number")
{
// The two lines below require UE v16.00 or UES v10.00 or later.
if (UltraEdit.activeDocument.lineTerminator == 1) sLineTerm = "\n";
else if (UltraEdit.activeDocument.lineTerminator == 2) sLineTerm = "\r";
}
else // This version of UE/UES does not offer line terminator property.
{
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\n"; // Not DOS, perhaps UNIX.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r"; // Also not UNIX, perhaps MAC.
if (UltraEdit.activeDocument.selection.indexOf(sLineTerm) < 0)
{
sLineTerm = "\r\n"; // No line terminator, use DOS.
}
}
}
}
// Get all lines of active file into an array of strings
// with each string being one line from active file.
var asLines = UltraEdit.activeDocument.selection.split(sLineTerm);
var nTotalLines = asLines.length;
// Process each line in the array.
for(var nCurrentLine = 0; nCurrentLine < asLines.length; nCurrentLine++)
{
// Skip all lines not containing or starting with an equal sign.
if (asLines[nCurrentLine].indexOf('=') < 1) continue;
// Get string left to equal sign with tabs/spaces trimmed.
var sKey = asLines[nCurrentLine].replace(/^[\t ]*([^\t =]+).*$/,"$1");
// Skip lines beginning with just tabs/spaces left to equal sign.
if (sKey.length == asLines[nCurrentLine].length) continue;
var_dump(sKey);
// Build the regular expression for the search in all other lines.
var rRegSearch = new RegExp("^[\\t ]*"+sKey+"[\\t ]*=","g");
// Ceck all remaining lines for a line also starting with
// this key string case-sensitive with left to an equal sign.
var nLineCompare = nCurrentLine + 1;
while(nLineCompare < asLines.length)
{
// Does this line also has this key left to equal
// sign with or without surrounding spaces/tabs?
if (asLines[nLineCompare].search(rRegSearch) < 0)
{
nLineCompare++; // No, continue on next line.
}
else // Yes, remove this line from array.
{
asLines.splice(nLineCompare,1);
}
}
}
// Was any line removed from the array?
if (nTotalLines == asLines.length)
{
UltraEdit.activeDocument.top(); // Cancel the selection.
UltraEdit.messageBox("Nothing found to remove!");
}
else
{
// If version of UE/UES supports direct write to clipboard, use
// user clipboard 9 to paste the lines into file with overwritting
// everything as this is much faster than using write command in
// older versions of UE/UES.
if (typeof(UltraEdit.clipboardContent) == "string")
{
var nActiveClipboard = UltraEdit.clipboardIdx;
UltraEdit.selectClipboard(9);
UltraEdit.clipboardContent = asLines.join(sLineTerm);
UltraEdit.activeDocument.paste();
UltraEdit.clearClipboard();
UltraEdit.selectClipboard(nActiveClipboard);
}
else UltraEdit.activeDocument.write(asLines.join(sLineTerm));
var nRemoved = nTotalLines - asLines.length;
UltraEdit.activeDocument.top();
UltraEdit.messageBox("Removed " + nRemoved + " line" + ((nRemoved != 1) ? "s" : "") + " on updated file.");
}
}
Copy this code and paste it into a new ASCII file using DOS line terminators in UltraEdit.
Next use command File - Save As to save the script file for example with name RemoveDuplicateKeys.js into %AppData%\IDMComp\UltraEdit\MyScripts or wherever you want to have saved your UltraEdit scripts.
Open Scripting - Scripts and add the just saved UltraEdit script to the list of scripts. You can enter a description for this script, too.
Open the file with the list, or make this file active if it is already opened in UltraEdit.
Run the script by clicking on it in menu Scripting, or by opening Views - Views/Lists - Script List and double clicking on the script.

Appending to end of line in eclipse

Is there a way to append string to the end of lines in Eclipse?
Search and find seems like it would work, but using find with just the regex expression $ does not find any strings. .$ will find something, but running find replace with this deletes the last character of your line, which is undesirable. Does anyone know a way to accomplish this in Eclipse? Is there something I am doing wrong with my regex that might make Eclipse not understand this, while other editors like vim handle it just fine.. (in Vi / Vim :0,$s/$/appended to end of line/).
Surely I am not the only person who wishes there was this functionality... It's offered by most other good editors. Could this be considered a bug?
I agree that this is a bug in eclipse. I tried the same as you with the same results. I also tried to use the regex search string "(?<=.)$" to try to ignore the single character match in the replace but that failed as well. One should be able to search for end of string to append.
Here's a trick to make it work,
Find: "(.)$"
Replace: $1foo
This replaces the single character match before the end of line and appends foo.
That's a lot of hoop jumping but at least it works.
I'm wondering if the best bet would be to run a Java program on the list of variables before you copy them in. I'm not sure of the format of the file which you have cut and paste from but if it is just a list with only the variable names on each line, try this:
ArrayList<String> importarray = new ArrayList<String>();
ArrayList<String> rebuildarray = new ArrayList<String>();
BufferedReader bufferedfile = new BufferedReader();
public static void main(String[] args) {
readFile();
processFile();
}
static void readFile() {
String file = "C:\\path\\file.txt";
try {
String line;
importstart = new BufferedReader(new FileReader(file));
for (line = importstart.readLine(); line != null; line = importstart.readLine()) {
importarray.add (line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static void processFile() {
String complete = "";
for (String string : importarray) {
complete = string + "\";";
rebuildarray.add(complete);
}
}
Adding this in would provide an array of variable names with " "; " on the end.
Alternatively, you could use this array in the String declaration and do:
for (String variable : rebuildarray) {
final String string = variable;
doSomething(string);
}
This would negate the need for the addition of ";.
Note sure if this is a bit too much, or even entirely what you were looking for, but they are a couple of ideas.
In my case, using Eclipse Luna (4.4.0), the accepted solution didn't work. It is only replacing the first line and leaving the others. But the worked (wanted to added a semi-colon):
find: ^.*$
Replace: $0;

Writing a large array in one line using jsoncpp's StyledWriter

I'm using jsoncpp to read and write json files.
For writing, I use the StyledWriter, which writes the json in a human readable fashion.
Currently, I'm trying to write an array of ints into a json file. The documentation describes the following rules for writing an array value:
if empty then print [] without indent and line break
if the array contains no object value, empty array or some other value types, and all the values fit on one lines, then print the array on a single line.
otherwise, if the values do not fit on one line, or the array contains object or non empty array, then print one value per line.
Since the array I'm trying to write is too big for one line, according to the rules above, the writer prints it one value per line, which makes my json ugly and less readable. I would prefer it to write the whole array in one line or in several lines, with several values per line.
I'm aware of the fact that jasoncpp is opensource and thus I can change the writer to do what I want,
but I'm wondering if there's a different way to do it. Maybe using both FastWriter (which creates a one-line-json) and StyledWriter?
You should use FastWriter as follows:
Json::Value your_json(Json::objectValue);
//init your json...
Json::FastWriter fastWriter;
fastWriter.write(your_json)
Look at json_writer.cpp - two writeIndent() methods.
void
StyledStreamWriter::writeIndent()
{
/*
Some comments in this method would have been nice. ;-)
if ( !document_.empty() )
{
char last = document_[document_.length()-1];
if ( last == ' ' ) // already indented
return;
if ( last != '\n' ) // Comments may add new-line
*document_ << '\n';
}
*/
//Removing indent and line feed!!! *document_ << '\n' << indentString_;
}
void
StyledWriter::writeIndent()
{
if ( !document_.empty() )
{
char last = document_[document_.length()-1];
if ( last == ' ' ) // already indented
return;
//Removing indent and line feed!!! if ( last != '\n' ) // Comments may add new-line
//Removing indent and line feed!!! document_ += '\n';
}
document_ += indentString_;
}

Match beginning of file to string literal

I'm working with a multi line text block where I need to divide everything into 3 groups
1: beginning of the file up to a string literal // don't keep
2: The next line //KEEP THE LINE FOLLOWING STRING LITERAL
3: Everything following that line to the end of file. // don't keep
<<
aFirstLing here
aSecondLine here
MyStringLiteral //marks the next line as the target to keep
What I want to Keep!
all kinds of crap that I don't
<<
I'm finding plenty of ways to pull from the beginning of a line but am unable to see how to include an unknown number of non-blank lines until I reach that string literal.
EDIT: I'm removing the .net-ness to focus on regex only. Perhaps this is a place for understanding backreferences?
Rather than read the entire file into memory, just read what you need:
List<string> TopLines = new List<string>();
string prevLine = string.Empty;
foreach (var link in File.ReadLines(filename))
{
TopLines.Add(line);
if (prevLine == Literal)
{
break;
}
prevLine = line;
}
I suppose there's a LINQ solution, although I don't know what it is.
EDIT:
If you already have the text of the email in you application (as a string), you have to split it into lines first. You can do that with String.Split, splitting on newlines, or you can create a StringReader and read it line-by-line. The logic above still applies, but rather than File.ReadLines, just use foreach on the array of lines.
EDIT 2:
The following LINQ might do it:
TopLines = File.ReadLines(filename).TakeWhile(s => s != Literal).ToList();
TopLines.Add(Literal);
Or, if the strings are already in a list:
TopLines = lines.TakeWhile(s => s != Literal).ToList();
TopLines.Add(Literal);
.*(^MyStringLiteral\r?\n)([\w|\s][^\r\n]+)(.+) seems to work. the trick wasn't back references - it was the exclusion of \r\n.
File.ReadAllLines() will give you an array you can iterate over until you find your literal, then take the next line
string[] lines = File.ReadAllLines();
for(int i;i<lines.Length;i++)
{
if(line == Literal)
return lines[i + 1];
}