Forums

Code Folding Strategy

General discussion about Cobra. Releases and general news will also be posted here.
Feel free to ask questions or just say "Hello".

Re: Code Folding Strategy

Postby torial » Tue Mar 01, 2011 9:37 pm

FWIW I will delete the screenshot, as I've made a separate thread for discussion for my editor and put it there.

RIGHT_THEN, this isn't for AvalonEdit but was for the prior version of the control: ICSharpCode.TextEditor, from the sample TextEditor project. I will switch my editor from the Alsing SyntaxBox to this, and work on fleshing it out over the next few weeks (and will keep any implementation of this interface posted)

Code: Select all
   /// <summary>
   /// The class to generate the foldings, it implements ICSharpCode.TextEditor.Document.IFoldingStrategy
   /// </summary>
   public class RegionFoldingStrategy : IFoldingStrategy
   {
      /// <summary>
      /// Generates the foldings for our document.
      /// </summary>
      /// <param name="document">The current document.</param>
      /// <param name="fileName">The filename of the document.</param>
      /// <param name="parseInformation">Extra parse information, not used in this sample.</param>
      /// <returns>A list of FoldMarkers.</returns>
      public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
      {
         List<FoldMarker> list = new List<FoldMarker>();

         Stack<int> startLines = new Stack<int>();
         
         // Create foldmarkers for the whole document, enumerate through every line.
         for (int i = 0; i < document.TotalNumberOfLines; i++)
         {
            var seg = document.GetLineSegment(i);
            int offs, end = document.TextLength;
            char c;
            for (offs = seg.Offset; offs < end && ((c = document.GetCharAt(offs)) == ' ' || c == '\t'); offs++)
               {}
            if (offs == end)
               break;
            int spaceCount = offs - seg.Offset;

            // now offs points to the first non-whitespace char on the line
            if (document.GetCharAt(offs) == '#') {
               string text = document.GetText(offs, seg.Length - spaceCount);
               if (text.StartsWith("#region"))
                  startLines.Push(i);
               if (text.StartsWith("#endregion") && startLines.Count > 0) {
                  // Add a new FoldMarker to the list.
                  int start = startLines.Pop();
                  list.Add(new FoldMarker(document, start,
                     document.GetLineSegment(start).Length,
                     i, spaceCount + "#endregion".Length));
               }
            }
         }
         
         return list;
      }
   }
torial
 
Posts: 229
Location: IA

Re: Code Folding Strategy

Postby torial » Wed Mar 02, 2011 11:43 pm

RIGHT_THEN,

I've got a working starting point for code folding (and I've fixed the issues I knew about before -- except for block comments)

Untested is the test/body/ensure/require scenarios... but I'm pretty confident they should work.

class CobraFoldingStrategy implements IFoldingStrategy
def generateFoldMarkers(document as IDocument, fileName as String?, parseInfo as Object?) as List<of FoldMarker>
result = List<of FoldMarker>()

regionStartLines = Stack<of int>()
blockStartLines = Stack<of KeyValuePair<of int,int>>()

currentLine = 0
for iLine in document.totalNumberOfLines
currentLine = iLine
seg = document.getLineSegment(iLine)
line = document.getText(seg)
trimmed = line.trim
currentIndent = line.length - trimmed.length

if trimmed.startsWith("#region")
regionStartLines.push(iLine)
else if trimmed.startsWith("#endregion") and regionStartLines.count > 0
start = regionStartLines.pop
result.add(FoldMarker(document,start,document.getLineSegment(start).length,iLine,currentIndent + "#endregion".length))
else if _isBlockScope(trimmed)
while blockStartLines.count > 0 and blockStartLines.peek.value >= currentIndent
#we know there is another block with the same start, so go ahead and close it out.
origStart = blockStartLines.pop
kvp = _getPriorNonCommentNonBlankLine(document,iLine)
endLine = kvp.key
endText = kvp.value
result.add(FoldMarker(document,origStart.key,document.getLineSegment(origStart.key).length, endLine,endText.length ))

blockStartLines.push(KeyValuePair<of int,int>(iLine,line.length-trimmed.length))
#close out any unmatched folds
while blockStartLines.count > 0
origStart = blockStartLines.pop
kvp = _getPriorNonCommentNonBlankLine(document,iLine)
endLine = kvp.key
endText = kvp.value
result.add(FoldMarker(document,origStart.key,document.getLineSegment(origStart.key).length, endLine,endText.length ))

return result

def _isBlockScope(l as String) as bool
return l.startsWith("cue ") or l.startsWith("def ") or l.startsWith("ensure") or l.startsWith("require") or l.startsWith("body") or l.startsWith("test") or l.startsWith("class ") or l.startsWith("namespace ")

def _getPriorNonCommentNonBlankLine(document as IDocument, iLine as int) as KeyValuePair<of int,String>
post while iLine > 0
iLine -=1
#TODO, support block comments /# #/
line = document.getText(document.getLineSegment(iLine))
trimmed = line.trim
if not trimmed.startsWith("#") and not trimmed.length == 0
return KeyValuePair<of int,String>(iLine,line)
return KeyValuePair<of int,String>(iLine,"")
torial
 
Posts: 229
Location: IA

Re: Code Folding Strategy

Postby RIGHT_THEN » Thu Mar 03, 2011 10:58 pm

Mr. Torial

thanks for the snippet so you are not using tokenizer then
if u keep up like this than soon Cobra might have its tools chain ready.

Thanking_You
RIGHT_THEN
RIGHT_THEN
 
Posts: 99

Re: Code Folding Strategy

Postby torial » Fri Mar 04, 2011 9:25 am

RIGHT_THEN wrote:thanks for the snippet so you are not using tokenizer then
if u keep up like this than soon Cobra might have its tools chain ready.


Btw, you can call me : Sean, "torial" is just a handle.

Yeah, I did a fast-and-dirty parsing approach, rather than a true tokenization scheme.

It'd be cool to spend this much time continuously, but I expect it is more because I'm writing SOPs at work right now instead of coding, so I've been doing the folding logic as a sort of "sanity" hobby.
torial
 
Posts: 229
Location: IA

Re: Code Folding Strategy

Postby RIGHT_THEN » Mon Mar 07, 2011 10:00 am

Charles

Is it correct to assume that dedents and indents are not vertical but
can be horizontal too!!
are you doing something like that in c-languages multiple braces at one place

class x{
public void func{
if(true)
{
}}} -> all three at one place

thats is how i have encountered dedents and indents in certain files

and also immediately after the Class \t of def is not recognised as indent
or do i need to recheck my code again ( which i did)
when it is immediately below class if doc-string is placed before that it become okay, is it correct??

apart from the above would it be allright for you to throw light on what is the textual
representation of indent and dedent or is it a logical palceholder to understand
the begining and end of the block.

Thanking_You
RIGHT_THEN
RIGHT_THEN
 
Posts: 99

Re: Code Folding Strategy

Postby Charles » Wed Mar 09, 2011 4:54 pm

Indent and dedent tokens are only about horizontal indentation and not anything to do with "vertical". They are logical tokens to represent additional indentation used by Cobra programmers for contained declarations and code blocks. Physically, an indent corresponds to a tab or four spaces. A dedent is used to back out of indentation and ultimately there will be one for each indent.

Since they have to balance, when you have code like:
class X
def foo
if true
pass

You will get 3 dedents in the end to match each of the indents.

I'm sorry, but I could not understand your later question about "...not recognised as indent...".

At the top of CobraWorkspace/Source/CobraTokenizer.cobra you will see a "test" section with some very small code samples and the expected token stream from them. This may help you.

Btw this same approach is used by Python. And Python IDEs, or at least one of them (WingIDE), offer code folding. I don't know what the implementation is, but I'm guessing it is based on the indent and dedent tokens.

HTH
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Code Folding Strategy

Postby RIGHT_THEN » Wed Mar 09, 2011 11:55 pm

Charles

Thanks for clearing it up.i have successfully implemented code folding. based on indent and
dedents but sometimes it just misses out on the class start indent/occasionally
which makes class not foldable but everything else inside it.(that is why i asked )
and also DOC-STRING_START of doc strings of the functions (sometimes).but anyway it is quite workable .
for anyone reading this post in 2055 who would want to implement code folding. start checking from
below the file rather than up and keep folding as you find pairs.that would make it a lot easier.

Thanking_You
RIGHT_THEN
RIGHT_THEN
 
Posts: 99

Re: Code Folding Strategy

Postby RIGHT_THEN » Sat Mar 19, 2011 7:46 am

Charles

indenDe.jpg
indenDe.jpg (55.39 KiB) Viewed 9758 times


Two Photos of same file { are indents and } are dedents

1) As you can see above the indent at Line 4 has been matched at dedent at Line 8
but indent at Line 3, which dedent should it consider its partner at line 9?
The first one or the second one.


2)As you said somewhere in your previous post that there will always be equal number of indents
and dedents in the file.So do i take it for granted that the Last indent of the file if does not
have a dedent after it than it would be on the same line before it.But which one of the Two??
first one or always the nearest one in this case the second one.

this is very important for me to know. Because it would help me in resolving the scopes
suppose someone presses a DOT "." by looking throught Indent and dedents i can figure it out
where it has been pressed inside of function body , class body or outside somewhere. then
to show appropiate members in the autocompletion help window. otherwise it is terrible to judge.

Thanking_You
RIGHT_THEN
RIGHT_THEN
 
Posts: 99

Re: Code Folding Strategy

Postby Charles » Sat Mar 19, 2011 10:30 am

I get the two DEDENTS at the end like so:
Code: Select all
CLASS/class  ID/Class3  EOL/\n  (1)
INDENT/  CUE/cue  OPEN_CALL/init(  RPAREN/)  EOL/\n  (2)
INDENT/  BASE/base  DOT/.  ID/init  EOL/\n  (3)
ID/x  ASSIGN/=  OPEN_CALL/Hello(  RPAREN/)  EOL/\n  (4)
ID/x  DOT/.  OPEN_CALL/sayHello(  STRING_SINGLE/'Class3'  RPAREN/)  EOL/\n  (5)
EOL/\n  (6)
DEDENT/  DEF/def  OPEN_CALL/add_1(  ID/num1  AS/as  INT/int  COMMA/,  ID/num2  AS/as  INT/int  RPAREN/)  AS/as  INT/int  EOL/\n  (7)
INDENT/  RETURN/return  ID/num1  PLUS/+  ID/num2  EOL/\n  DEDENT/  DEDENT/ 


Whereas in your screenshot you show the }} happening before the "return" which I find confusing.

I added this code to the compiler to get that output:
tokens = tokenizer.startSource(_fileName, source).allTokens
# added at CobraParser.cobra:233:
if true
print
print '-------------------------------------------------------------------'
lastToken as IToken?
for token in tokens
if lastToken and lastToken.lineNum < token.lineNum
print '([lastToken.lineNum])'
print '[token.which]/[token.text.toTechString[1:-1]] ' stop
lastToken = token
print

Regarding matching the DEDENT with an INDENT, I would think a DEDENT would match the most recent INDENT just like } matches the most recent {

Does that help?
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Code Folding Strategy

Postby RIGHT_THEN » Sat Mar 19, 2011 12:27 pm

Thanks for the info Charles

That is what was confusing me too. the sequence you produced is the logical one
and that is how it should be
So i checked my tokeniser code.
Indeed it produces the way yours has produced
i.e there are two DEDENTS in the end but still there is a catch
with me there column number is 1 and line number stays same as that of EOL
That is why there are two }} before { in the above post
if you could output this again with line and column number you will get the picture
or else there is a Bug in compiler i am using.

could you please get token list and run it in a loop to see the output of the Line and column
number of the tokens. something similar to
foreach (var tok in TokensList)
{
Console.WriteLine("{0} {1} {2} {3}",tok.LineNum,tok.ColNum,tok.Which,tok.ToTechString() );
}


the correct answer should be either LineNumber of DEDENTS greater than EOL`s (Linenumber)
or same lineNumber with ColNumber Greater than EOL`s ColumnNumber.

Thanking_You
RIGHT_THEN
RIGHT_THEN
 
Posts: 99

PreviousNext

Return to Discussion

Who is online

Users browsing this forum: No registered users and 37 guests