All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.projectnessie.nessie.cli.cli.NessieCliCompleter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2024 Dremio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.projectnessie.nessie.cli.cli;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.jline.reader.Candidate;
import org.jline.reader.LineReader;
import org.jline.reader.ParsedLine;
import org.jline.reader.impl.completer.SystemCompleter;
import org.projectnessie.client.NessieConfigConstants;
import org.projectnessie.error.NessieNotFoundException;
import org.projectnessie.model.Reference;
import org.projectnessie.nessie.cli.completer.CliCompleter;
import org.projectnessie.nessie.cli.grammar.CompletionType;
import org.projectnessie.nessie.cli.grammar.NessieCliParser;
import org.projectnessie.nessie.cli.grammar.Token.TokenType;

class NessieCliCompleter extends SystemCompleter {

  private static final List NESSIE_CONFIG_KEYS =
      Arrays.stream(NessieConfigConstants.class.getDeclaredFields())
          .filter(f -> f.getName().startsWith("CONF_"))
          .map(
              f -> {
                try {
                  return f.get(null);
                } catch (IllegalAccessException e) {
                  throw new RuntimeException(e);
                }
              })
          .map(String.class::cast)
          .filter(k -> k.startsWith("nessie."))
          .sorted()
          .collect(Collectors.toList());

  private final BaseNessieCli nessieCli;

  NessieCliCompleter(BaseNessieCli nessieCli) {
    this.nessieCli = nessieCli;
  }

  @Override
  public void complete(LineReader reader, ParsedLine line, List candidates) {
    new CliCompleter(
        line.line(),
        line.cursor(),
        nessieCli::newParserForSource,
        NessieCliParser::SingleStatement) {
      @Override
      protected void completeWithLiteral(
          CompletionType completionType, String preceding, String toComplete, boolean quoted) {
        switch (completionType) {
          case REFERENCE_NAME:
            AtomicInteger counter = new AtomicInteger();
            // TODO providing all (think: too many) reference names can "overwhelm" completion.
            //  JLine then warns with something like 'JLine terminal: do you wish to see all 218
            //  possibilities (14 lines)?', which is not nice and does not help.
            //  The implementation should not return "too many" options but enough (starting
            //  strings) to continue completion, so users do not have to see that warning.
            // TODO also pass 'toComplete', if not empty, as a filter down to Nessie
            // TODO also pass the reference type, if given, as a filter down to Nessie (need to know
            //  the statement parsed up to here :( )
            nessieCli
                .nessieApi()
                .ifPresent(
                    api -> {
                      try {
                        api.getAllReferences().stream()
                            .map(Reference::getName)
                            .forEach(refName -> candidate(refName, counter.getAndIncrement()));
                      } catch (NessieNotFoundException e) {
                        throw new RuntimeException(e);
                      }
                    });
            break;
          case CONNECT_OPTIONS:
            for (int i = 0; i < NESSIE_CONFIG_KEYS.size(); i++) {
              candidate("\"" + NESSIE_CONFIG_KEYS.get(i) + "\"", i);
            }
            break;
          case CONTENT_KEY:
            // TODO do something ?
            break;
          default:
            // do nothing - don't break anything
            break;
        }
      }

      @Override
      protected void tokenCandidateStartsWith(String preceding, TokenType toComplete) {
        candidate(toComplete, 1_000);
      }

      @Override
      protected void tokenCandidateContains(String preceding, TokenType toComplete) {
        candidate(toComplete, 2_000);
      }

      @Override
      protected void tokenCandidateOther(String preceding, TokenType toComplete) {
        candidate(toComplete, 3_000);
      }

      private void candidate(TokenType token, int offset) {
        candidate(parser().tokenToLiteral(token), offset);
      }

      private void candidate(String tokenString, int offset) {
        candidates.add(
            new Candidate(
                tokenString,
                tokenString,
                null,
                null,
                null,
                null,
                true,
                offset + candidates.size()));
      }
    }.tryStatement();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy