Erlang Plugin for NetBeans in Scala#7: Occurrences Finder
Caoyuan Blog - - February 13, 2009During the AST node visiting (AstNodeVisitor.scala), I’ve gathered a lot of variable definitions and their references, we can now try to get editor to mark these occurrences. There are preliminary functions in AstScope.scala, such as findOccurrences(AstItem). You can override AstDfn#isReferredBy(AstRef) and AstRef#isOccurence(AstRef) to get accurate reference relations. As the first step, I just simply judge the reference relation by the equation of names.
We’ll extends org.netbeans.modules.csl.api.OccurrencesFinder and implement:
run(pResult:ErlangParserResult, event:SchedulerEvent) :Unit
First, we try to get the AstItem which is at the caretPosition by rootScope.findItemAt(th, caretPosition), and verify if it’s a valid token.
Then, by calling rootScope.findOccurrences(item), we collect all occurrences of this item, and put a ColoringAttributes.MARK_OCCURRENCES with its OffsetRange.
The code of ErlangOccurrencesFinder.scala:
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * * Contributor(s): * * Portions Copyrighted 2009 Sun Microsystems, Inc. */
package org.netbeans.modules.erlang.editor import _root_.java.util.{HashMap,List,Map}
import javax.swing.text.Document
import org.netbeans.api.lexer.{Token,TokenId,TokenHierarchy}
import _root_.org.netbeans.modules.csl.api.{ColoringAttributes,OccurrencesFinder,OffsetRange}
import org.netbeans.modules.parsing.spi.Parser
import org.netbeans.modules.parsing.spi.{Scheduler,SchedulerEvent}
import org.netbeans.modules.erlang.editor.ast.{AstDfn,AstItem,AstRef,AstRootScope}
import org.netbeans.modules.erlang.editor.lexer.{ErlangTokenId,LexUtil}
import org.openide.filesystems.FileObject /** * * @author Caoyuan Deng */
class ErlangOccurrencesFinder extends OccurrencesFinder[ErlangParserResult] { protected var cancelled = false private var caretPosition = 0 private var occurrences :Map[OffsetRange, ColoringAttributes] = _ private var file :FileObject = _ protected def isCancelled = synchronized {cancelled} protected def resume :Unit = synchronized {cancelled = false} override def getPriority = 0 override def getSchedulerClass = Scheduler.CURSOR_SENSITIVE_TASK_SCHEDULER override def getOccurrences :Map[OffsetRange, ColoringAttributes] = occurrences override def cancel :Unit = synchronized {cancelled = true} override def setCaretPosition(position:Int) :Unit = {this.caretPosition = position} def run(pResult:ErlangParserResult, event:SchedulerEvent) :Unit = { resume if (pResult == null || isCancelled) { return } val currentFile = pResult.getSnapshot.getSource.getFileObject if (currentFile != file) { // Ensure that we don't reuse results from a different file occurrences = null file = currentFile } for (rootScope <- pResult.rootScope; th <- LexUtil.tokenHierarchy(pResult); doc <- LexUtil.document(pResult, true); // * we'll find item by offset of item's idToken, so, use caretPosition directly item <- rootScope.findItemAt(th, caretPosition); idToken <- item.idToken ) { var highlights = new HashMap[OffsetRange, ColoringAttributes](100) val astOffset = LexUtil.astOffset(pResult, caretPosition) if (astOffset == -1) { return } // * When we sanitize the line around the caret, occurrences // * highlighting can get really ugly val blankRange = pResult.sanitizedRange if (blankRange.containsInclusive(astOffset)) { return } // * test if document was just closed? LexUtil.document(pResult, true) match { case None => return case _ => } try { doc.readLock val length = doc.getLength val astRange = LexUtil.rangeOfToken(th.asInstanceOf[TokenHierarchy[TokenId]], idToken.asInstanceOf[Token[TokenId]]) val lexRange = LexUtil.lexerOffsets(pResult, astRange) var lexStartPos = lexRange.getStart var lexEndPos = lexRange.getEnd // If the buffer was just modified where a lot of text was deleted, // the parse tree positions could be pointing outside the valid range if (lexStartPos > length) { lexStartPos = length } if (lexEndPos > length) { lexEndPos = length } LexUtil.token(doc, caretPosition) match { case None => return case token => // valid token, go on } } finally { doc.readUnlock } val _occurrences = rootScope.findOccurrences(item) for (_item <- _occurrences; _idToken <- _item.idToken ) { highlights.put(LexUtil.rangeOfToken(th.asInstanceOf[TokenHierarchy[TokenId]], _idToken.asInstanceOf[Token[TokenId]]), ColoringAttributes.MARK_OCCURRENCES) } if (isCancelled) { return } if (highlights.size > 0) { val translated = new HashMap[OffsetRange, ColoringAttributes](2 * highlights.size) val entries = highlights.entrySet.iterator while (entries.hasNext) { val entry = entries.next LexUtil.lexerOffsets(pResult, entry.getKey) match { case OffsetRange.NONE => case range => translated.put(range, entry.getValue) } } highlights = translated this.occurrences = highlights } else { this.occurrences = null } } }
}
Finally, again, register it in ErlangLanguage.scala
override def hasOccurrencesFinder = true override def getOccurrencesFinder = new ErlangOccurrencesFinder
And add mark-occurrences effect setting in fontsColors.xml:
<fontcolor name="mark-occurrences" bgColor="ECEBA3"/>
That’s all. Run it, you got:
Var LogPid’s definition and references were highlighted now.
The correctness of occurrences marking depends on the correctness of scopes of variables when you visit AST node, I did not finish all of such work yet, but, enabling occurrences marking feature is very helpful for further work.
Categories: Blogs Caoyuan Blog
Comments
No comments so far, you could be the first.Add comment
Erlang on Twitter
» JafarAL (Jafar ALi ALatas): Ktemu dewa erlang sm sun go kong RT @JulianCAL: Ke langit ke-7 RT @JafarAL: Kmana malam ini ? Yg gak macet..
» VaiguntaSarathy (Vaigunta Sarathy): FS#29929: [erlang] Simplify PKGBUILD http://t.co/rDJ85DMb
» vadson27 (vadson ferreira): FS#29929: [erlang] Simplify PKGBUILD http://t.co/6Oox4Ehf
» vaibhavsingh544 (Vabhav Singh): FS#29929: [erlang] Simplify PKGBUILD http://t.co/Sjhjc2aM
» vaccumakeh (Vladimir Rostov): FS#29929: [erlang] Simplify PKGBUILD http://t.co/S86CjIjg
» ITJobs_EU_UK (ITJobs_EU_UK): #JB Ruby Developer ( Ruby / RoR Erlang LAMP ): Job Description : Ruby Developer / Software Engineer Location: Lo… http://t.co/74omWQ9m
» udzura (Uchio KONDO): 文字列操作が弱い、は今のErlangではfalseであると
» udzura (Uchio KONDO): Erlang , R14 あたりからutf-8の文字列の扱いに強くなったとのこと #shinjukuex
» winda_lestari63 (winda cliquers): gg usja di pikirin prins ank itw gjhe..RT:@Prinsia_2140
@Erlang_ABNIC @ji_bero @erlang_abnic @rb_120511
» ErlangSolutions (Erlang Solutions): Want to join the best of the best of the best? ESL is hiring 40 engineers! Join our Linkedin Group to keep updated http://t.co/CDB7qYeI
Statistics
Number of aggregated posts: 10498
Number of comments: 2115
Most recent article: May 15, 2012
Latest comments
» cheap soccer jerseys on Memory Models in Erlang vs Java: Nice discussion here,you are doing a great job. i was looking for this information. i found it on your page…
» mandesejohn on Couchbase Meetup at new HQ: Thanks for sharing experience. It should be really a great post. It should be knowledgeable and informative. Keep it up. flower delivery columbus ohio
» vermaseo on Scale means Skills: I’m surprised people are still commenting about this. George has been moved on to bigger and better things with the president for awhile now.ledikanten
