@@ -300,17 +300,8 @@ private List<Suggestion> completionSuggestionsImpl(String code, int cursor, int[
300300 identifier = m .group ();
301301 }
302302 }
303- code = code .substring (0 , cursor );
304- if (code .trim ().isEmpty ()) { //TODO: comment handling
305- code += ";" ;
306- }
307- boolean [] moduleImport = new boolean [1 ];
308- OuterWrap codeWrap = switch (guessKind (code , moduleImport )) {
309- case IMPORT -> moduleImport [0 ] ? proc .outerMap .wrapImport (Wrap .simpleWrap (code ), null )
310- : proc .outerMap .wrapImport (Wrap .simpleWrap (code + "any.any" ), null );
311- case CLASS , METHOD -> proc .outerMap .wrapInTrialClass (Wrap .classMemberWrap (code ));
312- default -> proc .outerMap .wrapInTrialClass (Wrap .methodWrap (code ));
313- };
303+
304+ OuterWrap codeWrap = wrapCodeForCompletion (code , cursor , true );
314305 String [] requiredPrefix = new String [] {identifier };
315306 return computeSuggestions (codeWrap , code , cursor , requiredPrefix , anchor ).stream ()
316307 .filter (s -> filteringText (s ).startsWith (requiredPrefix [0 ]) && !s .continuation ().equals (REPL_DOESNOTMATTER_CLASS_NAME ))
@@ -1740,15 +1731,11 @@ public List<Documentation> documentation(String code, int cursor, boolean comput
17401731 };
17411732
17421733 private List <Documentation > documentationImpl (String code , int cursor , boolean computeJavadoc ) {
1743- code = code .substring (0 , cursor );
1744- if (code .trim ().isEmpty ()) { //TODO: comment handling
1745- code += ";" ;
1746- }
1747-
1748- if (guessKind (code ) == Kind .IMPORT )
1734+ OuterWrap codeWrap = wrapCodeForCompletion (code , cursor , false );
1735+ if (codeWrap == null ) {
1736+ //import:
17491737 return Collections .emptyList ();
1750-
1751- OuterWrap codeWrap = proc .outerMap .wrapInTrialClass (Wrap .methodWrap (code ));
1738+ }
17521739 return proc .taskFactory .analyze (codeWrap , List .of (keepParameterNames ), at -> {
17531740 SourcePositions sp = at .trees ().getSourcePositions ();
17541741 CompilationUnitTree topLevel = at .firstCuTree ();
@@ -2434,6 +2421,99 @@ public static void waitCurrentBackgroundTasksFinished() throws Exception {
24342421 INDEXER .submit (() -> {}).get ();
24352422 }
24362423
2424+ private OuterWrap wrapCodeForCompletion (String code , int cursor , boolean wrapImports ) {
2425+ code = code .substring (0 , cursor );
2426+ if (code .trim ().isEmpty ()) { //TODO: comment handling
2427+ code += ";" ;
2428+ }
2429+
2430+ List <String > imports = new ArrayList <>();
2431+ List <Wrap > declarationParts = new ArrayList <>();
2432+ String lastImport = null ;
2433+ boolean lastImportIsModuleImport = false ;
2434+ Wrap declarationWrap = null ;
2435+ Wrap pendingWrap = null ;
2436+ String input = code ;
2437+ boolean cont = true ;
2438+ int startOffset = 0 ;
2439+
2440+ while (cont ) {
2441+ if (lastImport != null ) {
2442+ imports .add (lastImport );
2443+ lastImport = null ;
2444+ }
2445+ if (declarationWrap != null ) {
2446+ declarationParts .add (declarationWrap );
2447+ declarationWrap = null ;
2448+ pendingWrap = null ;
2449+ }
2450+
2451+ String current ;
2452+ SourceCodeAnalysis .CompletionInfo completeness = analyzeCompletion (input );
2453+ int newStartOffset ;
2454+
2455+ if (completeness .completeness ().isComplete () && !completeness .remaining ().isBlank ()) {
2456+ current = input .substring (0 , input .length () - completeness .remaining ().length ());
2457+ newStartOffset = startOffset + input .length () - completeness .remaining ().length ();
2458+ input = completeness .remaining ();
2459+ cont = true ;
2460+ } else {
2461+ current = input ;
2462+ cont = false ;
2463+ newStartOffset = startOffset ;
2464+ }
2465+
2466+ boolean [] moduleImport = new boolean [1 ];
2467+
2468+ switch (guessKind (current , moduleImport )) {
2469+ case IMPORT -> {
2470+ lastImport = current ;
2471+ lastImportIsModuleImport = moduleImport [0 ];
2472+ }
2473+ case CLASS , METHOD -> {
2474+ pendingWrap = declarationWrap = Wrap .classMemberWrap (whitespaces (code , startOffset ) + current );
2475+ }
2476+ case VARIABLE -> {
2477+ declarationWrap = Wrap .classMemberWrap (whitespaces (code , startOffset ) + current );
2478+ pendingWrap = Wrap .methodWrap (whitespaces (code , startOffset ) + current );
2479+ }
2480+ default -> {
2481+ pendingWrap = declarationWrap = Wrap .methodWrap (whitespaces (code , startOffset ) + current );
2482+ }
2483+ }
2484+
2485+ startOffset = newStartOffset ;
2486+ }
2487+
2488+ if (lastImport != null ) {
2489+ if (wrapImports ) {
2490+ return proc .outerMap .wrapImport (Wrap .simpleWrap (whitespaces (code , startOffset ) + lastImport + (!lastImportIsModuleImport ? "any.any" : "" )), null );
2491+ } else {
2492+ return null ;
2493+ }
2494+ }
2495+
2496+ if (pendingWrap != null ) {
2497+ return proc .outerMap .wrapInTrialClass (imports , declarationParts , pendingWrap );
2498+ }
2499+
2500+ throw new IllegalStateException ("No pending wrap for: " + code );
2501+ }
2502+
2503+ private static String whitespaces (String input , int offset ) {
2504+ StringBuilder result = new StringBuilder ();
2505+
2506+ for (int i = 0 ; i < offset ; i ++) {
2507+ if (input .charAt (i ) == '\n' ) {
2508+ result .append ('\n' );
2509+ } else {
2510+ result .append (' ' );
2511+ }
2512+ }
2513+
2514+ return result .toString ();
2515+ }
2516+
24372517 /**
24382518 * A candidate for continuation of the given user's input.
24392519 */
0 commit comments