66import java .util .Arrays ;
77import java .util .Collections ;
88import java .util .concurrent .CompletableFuture ;
9+ import java .util .concurrent .ExecutionException ;
910import java .util .HashSet ;
1011import java .util .List ;
1112import java .util .Map ;
1213import java .util .Optional ;
1314import java .util .Set ;
1415import java .util .stream .Collectors ;
1516import java .util .stream .IntStream ;
17+
1618import org .eclipse .lsp4j .CompletionItem ;
1719import org .eclipse .lsp4j .CompletionItemKind ;
1820import org .eclipse .lsp4j .Diagnostic ;
1921import org .eclipse .lsp4j .DiagnosticSeverity ;
2022import org .eclipse .lsp4j .InsertTextFormat ;
23+ import org .eclipse .lsp4j .Location ;
2124import org .eclipse .lsp4j .jsonrpc .CompletableFutures ;
2225import org .eclipse .lsp4j .Position ;
2326import org .eclipse .lsp4j .PublishDiagnosticsParams ;
2427import org .eclipse .lsp4j .Range ;
2528import org .eclipse .lsp4j .services .LanguageClient ;
2629import org .eclipse .lsp4j .TextEdit ;
2730import org .jsoup .Jsoup ;
31+
2832import processing .app .Base ;
2933import processing .app .contrib .ModeContribution ;
3034import processing .app .Platform ;
4145import processing .mode .java .PreprocService ;
4246import processing .mode .java .PreprocSketch ;
4347
48+ import static java .util .Arrays .copyOfRange ;
4449
4550class PdeAdapter {
4651 File rootPath ;
@@ -54,6 +59,7 @@ class PdeAdapter {
5459 CompletableFuture <PreprocSketch > cps ;
5560 CompletionGenerator suggestionGenerator ;
5661 Set <URI > prevDiagnosticReportUris = new HashSet <>();
62+ PreprocSketch ps ;
5763
5864
5965 PdeAdapter (File rootPath , LanguageClient client ) {
@@ -104,6 +110,41 @@ static Offset toLineCol(String s, int offset) {
104110 return new Offset (line , col );
105111 }
106112
113+
114+ /**
115+ * Converts a tabOffset to a position within a tab
116+ * @param program current code(text) from a tab
117+ * @param tabOffset character offset inside a tab
118+ * @return Position(line and col) within the tab
119+ */
120+ static Position toPosition (String program , int tabOffset ){
121+ Offset offset = toLineCol (program , tabOffset );
122+ return new Position (offset .line , offset .col -1 );
123+ }
124+
125+
126+ /**
127+ * Converts a range (start to end offset) to a location.
128+ * @param program current code(text) from a tab
129+ * @param startTabOffset starting character offset inside a tab
130+ * @param stopTabOffset ending character offset inside a tab
131+ * @param uri uri from a tab
132+ * @return Range inside a file
133+ */
134+ static Location toLocation (
135+ String program ,
136+ int startTabOffset ,
137+ int stopTabOffset ,
138+ URI uri
139+ ){
140+ Position startPos = toPosition (program , startTabOffset );
141+ Position stopPos = toPosition (program , stopTabOffset );
142+
143+ Range range = new Range (startPos , stopPos );
144+ return new Location (uri .toString (), range );
145+ }
146+
147+
107148 static void init () {
108149 Base .setCommandLine ();
109150 Platform .init ();
@@ -116,6 +157,10 @@ void notifySketchChanged() {
116157 preprocService .notifySketchChanged ();
117158 errorChecker .notifySketchChanged ();
118159 preprocService .whenDone (cps ::complete );
160+ try { ps = cps .get ();
161+ } catch (InterruptedException | ExecutionException e ) {
162+ throw new RuntimeException (e );
163+ }
119164 }
120165
121166 Optional <SketchCode > findCodeByUri (URI uri ) {
@@ -126,6 +171,59 @@ Optional<SketchCode> findCodeByUri(URI uri) {
126171 );
127172 }
128173
174+
175+ /**
176+ * Looks for the tab number for a given text
177+ * @param code text(code) from a tab
178+ * @return tabIndex where the code belongs to, or empty
179+ */
180+ public Optional <Integer > findTabIndex (SketchCode code ){
181+ int tabsCount = sketch .getCodeCount ();
182+ java .util .OptionalInt optionalTabIndex ;
183+ optionalTabIndex = IntStream .range (0 , tabsCount )
184+ .filter (i -> sketch .getCode (i ).equals (code ))
185+ .findFirst ();
186+
187+ if (optionalTabIndex .isEmpty ()){
188+ return Optional .empty ();
189+ }
190+
191+ return Optional .of (optionalTabIndex .getAsInt ());
192+ }
193+
194+
195+ /**
196+ * Looks for the javaOffset, this offset is the character position inside the
197+ * full java file. The position can be used by the AST to find a node.
198+ * @param uri uri of the file(tab) where to look
199+ * @param line line number
200+ * @param col column number
201+ * @return character offset within the full AST
202+ */
203+ public Optional <Integer > findJavaOffset (URI uri , int line , int col ){
204+
205+ Optional <SketchCode > optionalCode = findCodeByUri (uri );
206+ if (optionalCode .isEmpty ()){
207+ System .out .println ("couldn't find sketch code" );
208+ return Optional .empty ();
209+ }
210+ SketchCode code = optionalCode .get ();
211+
212+ Optional <Integer > optionalTabIndex = findTabIndex (code );
213+ if (optionalTabIndex .isEmpty ()){
214+ System .out .println ("couldn't find tab index" );
215+ return Optional .empty ();
216+ }
217+ int tabIndex = optionalTabIndex .get ();
218+
219+ String [] codeLines = copyOfRange (code .getProgram ().split ("\n " ), 0 ,line );
220+ String codeString = String .join ("\n " , codeLines );
221+ int tabOffset = codeString .length () + col ;
222+
223+ return Optional .of (ps .tabOffsetToJavaOffset (tabIndex , tabOffset ));
224+ }
225+
226+
129227 void updateProblems (List <Problem > problems ) {
130228 Map <URI , List <Diagnostic >> dias = problems .stream ()
131229 .map (prob -> {
0 commit comments