23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package jdk.internal.jshell.tool; |
26 package jdk.internal.jshell.tool; |
27 |
27 |
|
28 import jdk.jshell.SourceCodeAnalysis.Documentation; |
28 import jdk.jshell.SourceCodeAnalysis.QualifiedNames; |
29 import jdk.jshell.SourceCodeAnalysis.QualifiedNames; |
29 import jdk.jshell.SourceCodeAnalysis.Suggestion; |
30 import jdk.jshell.SourceCodeAnalysis.Suggestion; |
30 |
31 |
31 import java.awt.event.ActionListener; |
32 import java.awt.event.ActionListener; |
32 import java.io.IOException; |
33 import java.io.IOException; |
33 import java.io.InputStream; |
34 import java.io.InputStream; |
34 import java.io.InterruptedIOException; |
35 import java.io.InterruptedIOException; |
35 import java.io.PrintStream; |
36 import java.io.PrintStream; |
36 import java.io.UncheckedIOException; |
37 import java.io.UncheckedIOException; |
37 import java.lang.reflect.Method; |
|
38 import java.util.ArrayList; |
38 import java.util.ArrayList; |
|
39 import java.util.Arrays; |
39 import java.util.Collection; |
40 import java.util.Collection; |
40 import java.util.Collections; |
41 import java.util.Collections; |
41 import java.util.HashMap; |
42 import java.util.HashMap; |
|
43 import java.util.Iterator; |
42 import java.util.List; |
44 import java.util.List; |
43 import java.util.Locale; |
45 import java.util.Locale; |
44 import java.util.Map; |
46 import java.util.Map; |
45 import java.util.Objects; |
47 import java.util.Objects; |
46 import java.util.Optional; |
48 import java.util.Optional; |
47 import java.util.function.Supplier; |
49 import java.util.function.Function; |
48 import java.util.prefs.BackingStoreException; |
50 import java.util.prefs.BackingStoreException; |
49 import java.util.stream.Collectors; |
51 import java.util.stream.Collectors; |
50 import java.util.stream.Stream; |
52 import java.util.stream.Stream; |
51 |
53 |
|
54 import jdk.internal.shellsupport.doc.JavadocFormatter; |
52 import jdk.internal.jline.NoInterruptUnixTerminal; |
55 import jdk.internal.jline.NoInterruptUnixTerminal; |
53 import jdk.internal.jline.Terminal; |
56 import jdk.internal.jline.Terminal; |
54 import jdk.internal.jline.TerminalFactory; |
57 import jdk.internal.jline.TerminalFactory; |
55 import jdk.internal.jline.TerminalSupport; |
58 import jdk.internal.jline.TerminalSupport; |
56 import jdk.internal.jline.WindowsTerminal; |
59 import jdk.internal.jline.WindowsTerminal; |
57 import jdk.internal.jline.console.ConsoleReader; |
60 import jdk.internal.jline.console.ConsoleReader; |
|
61 import jdk.internal.jline.console.CursorBuffer; |
58 import jdk.internal.jline.console.KeyMap; |
62 import jdk.internal.jline.console.KeyMap; |
59 import jdk.internal.jline.console.UserInterruptException; |
63 import jdk.internal.jline.console.UserInterruptException; |
60 import jdk.internal.jline.console.completer.Completer; |
64 import jdk.internal.jline.console.completer.Completer; |
61 import jdk.internal.jline.console.history.History; |
65 import jdk.internal.jline.console.history.History; |
62 import jdk.internal.jline.console.history.MemoryHistory; |
66 import jdk.internal.jline.console.history.MemoryHistory; |
257 "\033\012", //Alt-Enter (Linux) |
261 "\033\012", //Alt-Enter (Linux) |
258 "\033\133\061\067\176", //F6/Alt-F1 (Mac) |
262 "\033\133\061\067\176", //F6/Alt-F1 (Mac) |
259 "\u001BO3P" //Alt-F1 (Linux) |
263 "\u001BO3P" //Alt-F1 (Linux) |
260 }; |
264 }; |
261 |
265 |
|
266 private String lastDocumentationBuffer; |
|
267 private int lastDocumentationCursor = (-1); |
|
268 |
262 private void documentation(JShellTool repl) { |
269 private void documentation(JShellTool repl) { |
263 String buffer = in.getCursorBuffer().buffer.toString(); |
270 String buffer = in.getCursorBuffer().buffer.toString(); |
264 int cursor = in.getCursorBuffer().cursor; |
271 int cursor = in.getCursorBuffer().cursor; |
265 String doc; |
272 boolean firstInvocation = !buffer.equals(lastDocumentationBuffer) || cursor != lastDocumentationCursor; |
|
273 lastDocumentationBuffer = buffer; |
|
274 lastDocumentationCursor = cursor; |
|
275 List<String> doc; |
|
276 String seeMore; |
|
277 Terminal term = in.getTerminal(); |
266 if (prefix.isEmpty() && buffer.trim().startsWith("/")) { |
278 if (prefix.isEmpty() && buffer.trim().startsWith("/")) { |
267 doc = repl.commandDocumentation(buffer, cursor); |
279 doc = Arrays.asList(repl.commandDocumentation(buffer, cursor, firstInvocation)); |
|
280 seeMore = "jshell.console.see.help"; |
268 } else { |
281 } else { |
269 doc = repl.analysis.documentation(prefix + buffer, cursor + prefix.length()); |
282 JavadocFormatter formatter = new JavadocFormatter(term.getWidth(), |
|
283 term.isAnsiSupported()); |
|
284 Function<Documentation, String> convertor; |
|
285 if (firstInvocation) { |
|
286 convertor = d -> d.signature(); |
|
287 } else { |
|
288 convertor = d -> formatter.formatJavadoc(d.signature(), |
|
289 d.javadoc() != null ? d.javadoc() |
|
290 : repl.messageFormat("jshell.console.no.javadoc")); |
|
291 } |
|
292 doc = repl.analysis.documentation(prefix + buffer, cursor + prefix.length(), !firstInvocation) |
|
293 .stream() |
|
294 .map(convertor) |
|
295 .collect(Collectors.toList()); |
|
296 seeMore = "jshell.console.see.javadoc"; |
270 } |
297 } |
271 |
298 |
272 try { |
299 try { |
273 if (doc != null) { |
300 if (doc != null && !doc.isEmpty()) { |
274 in.println(); |
301 if (firstInvocation) { |
275 in.println(doc); |
302 in.println(); |
276 in.redrawLine(); |
303 in.println(doc.stream().collect(Collectors.joining("\n"))); |
277 in.flush(); |
304 in.println(repl.messageFormat(seeMore)); |
|
305 in.redrawLine(); |
|
306 in.flush(); |
|
307 } else { |
|
308 in.println(); |
|
309 |
|
310 int height = term.getHeight(); |
|
311 String lastNote = ""; |
|
312 |
|
313 PRINT_DOC: for (Iterator<String> docIt = doc.iterator(); docIt.hasNext(); ) { |
|
314 String currentDoc = docIt.next(); |
|
315 String[] lines = currentDoc.split("\n"); |
|
316 int firstLine = 0; |
|
317 |
|
318 PRINT_PAGE: while (true) { |
|
319 int toPrint = height - 1; |
|
320 |
|
321 while (toPrint > 0 && firstLine < lines.length) { |
|
322 in.println(lines[firstLine++]); |
|
323 toPrint--; |
|
324 } |
|
325 |
|
326 if (firstLine >= lines.length) { |
|
327 break; |
|
328 } |
|
329 |
|
330 lastNote = repl.getResourceString("jshell.console.see.next.page"); |
|
331 in.print(lastNote + ConsoleReader.RESET_LINE); |
|
332 in.flush(); |
|
333 |
|
334 while (true) { |
|
335 int r = in.readCharacter(); |
|
336 |
|
337 switch (r) { |
|
338 case ' ': continue PRINT_PAGE; |
|
339 case 'q': |
|
340 case 3: |
|
341 break PRINT_DOC; |
|
342 default: |
|
343 in.beep(); |
|
344 break; |
|
345 } |
|
346 } |
|
347 } |
|
348 |
|
349 if (docIt.hasNext()) { |
|
350 lastNote = repl.getResourceString("jshell.console.see.next.javadoc"); |
|
351 in.print(lastNote + ConsoleReader.RESET_LINE); |
|
352 in.flush(); |
|
353 |
|
354 while (true) { |
|
355 int r = in.readCharacter(); |
|
356 |
|
357 switch (r) { |
|
358 case ' ': continue PRINT_DOC; |
|
359 case 'q': |
|
360 case 3: |
|
361 break PRINT_DOC; |
|
362 default: |
|
363 in.beep(); |
|
364 break; |
|
365 } |
|
366 } |
|
367 } |
|
368 } |
|
369 //clear the "press space" line: |
|
370 in.getCursorBuffer().buffer.replace(0, buffer.length(), lastNote); |
|
371 in.getCursorBuffer().cursor = 0; |
|
372 in.killLine(); |
|
373 in.getCursorBuffer().buffer.append(buffer); |
|
374 in.getCursorBuffer().cursor = cursor; |
|
375 in.redrawLine(); |
|
376 in.flush(); |
|
377 } |
278 } else { |
378 } else { |
279 in.beep(); |
379 in.beep(); |
280 } |
380 } |
281 } catch (IOException ex) { |
381 } catch (IOException ex) { |
282 throw new IllegalStateException(ex); |
382 throw new IllegalStateException(ex); |