diff --git a/app/build.gradle b/app/build.gradle index 2848520a6..5d27b5d6e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,10 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' -apply plugin: com.github.megatronking.stringfog.plugin.StringFogPlugin + +if(rootProject.ext.stringfogEnabled) { + apply plugin: com.github.megatronking.stringfog.plugin.StringFogPlugin +} android { compileSdkVersion rootProject.ext.compileSdk @@ -61,13 +64,11 @@ android { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug - stringfog.enable false } release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release - stringfog.enable true } } @@ -79,10 +80,12 @@ android { } } -stringfog { - key 'WVV0aGMwaEFZVzVFVW05SlJFbGtaUT09' - enable true - implementation 'com.github.megatronking.stringfog.xor.StringFogImpl' +if(rootProject.ext.stringfogEnabled) { + stringfog { + key 'WVV0aGMwaEFZVzVFVW05SlJFbGtaUT09' + enable true + implementation 'com.github.megatronking.stringfog.xor.StringFogImpl' + } } task copyBindings(type: Copy) { @@ -114,7 +117,7 @@ dependencies { implementation 'androidx.annotation:annotation:1.2.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.1' implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' implementation 'androidx.drawerlayout:drawerlayout:1.1.1' implementation 'androidx.gridlayout:gridlayout:1.0.0' @@ -126,7 +129,7 @@ dependencies { implementation 'com.google.android.material:material:1.4.0' // Firebase - implementation platform('com.google.firebase:firebase-bom:28.1.0') + implementation platform('com.google.firebase:firebase-bom:28.4.2') implementation 'com.google.firebase:firebase-analytics' implementation 'com.google.firebase:firebase-crashlytics' implementation 'com.google.firebase:firebase-messaging' @@ -137,8 +140,7 @@ dependencies { implementation project(':emulator') implementation project(':emulatorview') implementation project(':javapoet') - - api project(':lemminx') + implementation project(':lsp') // LSP4J implementation 'org.eclipse.lsp4j:org.eclipse.lsp4j:0.12.0' diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java index 214df4cbc..470bc03fc 100644 --- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -996,10 +996,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F Optional result = LSP.Java.init(mProject.getProjectPath()); LSP.Java.initialized(); }); - LSP.XML.start(() -> { - Optional result = LSP.XML.init(mProject.getProjectPath()); - LSP.XML.initialized(); - }); } private void getProjectFromIntent() { diff --git a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java index 4e316f3d4..980201aa1 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java +++ b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java @@ -285,7 +285,7 @@ public class EditorFragment extends BaseFragment implements EditorEventListener mBinding.editor.setEditorLanguage(new EmptyLanguage()); } - // File must be set only after setting the language server + // File must be set only after setting the language // This will make sure that textDocument/didOpen is sent mBinding.editor.setFile(getFile()); diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java index 69b7e457d..95dedfec6 100644 --- a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java @@ -16,7 +16,7 @@ public class GroovyAutoComplete implements AutoCompleteProvider { private static final List OTHERS = createOtherCompletions(); @Override - public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception { + public List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception { List result = new ArrayList<>(); for(String artifact : ANDROIDX_ARTIFACTS) { diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java index 5f2dcb325..9bedc33c7 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java @@ -22,7 +22,7 @@ public class JavaAutoComplete implements AutoCompleteProvider { private CompletableFuture, CompletionList>> future; @Override - public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception { + public List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception { IDELanguageServer languageServer = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_JAVA); if(languageServer != null && fileUri != null) { diff --git a/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java b/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java index 09b6b32e6..7e944702c 100644 --- a/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java +++ b/app/src/main/java/com/itsaky/androidide/language/logs/LogLanguageImpl.java @@ -105,7 +105,7 @@ public class LogLanguageImpl extends BaseLanguage { private static class LogCompletor implements AutoCompleteProvider { @Override - public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { + public List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { return new ArrayList(); } } diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java index db3ee6531..ecf5f6db3 100644 --- a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java @@ -1,72 +1,34 @@ package com.itsaky.androidide.language.xml; -import com.itsaky.androidide.lsp.LSPProvider; -import com.itsaky.lsp.services.IDELanguageServer; +import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.language.xml.completion.XMLCompletionService; +import com.itsaky.androidide.utils.Logger; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.text.TextAnalyzeResult; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.CompletionList; -import org.eclipse.lsp4j.CompletionParams; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import com.itsaky.androidide.utils.Logger; public class XMLAutoComplete implements AutoCompleteProvider { - + private static final Logger LOG = Logger.instance("XMLAutoComplete"); private Comparator RESULTS_SORTER = new Comparator(){ @Override public int compare(CompletionItem p1, CompletionItem p2) { - if(p1.getSortText() == null && p1.getSortText() != null) return -1; - if(p1.getSortText() != null && p1.getSortText() == null) return 1; - if(p1.getSortText() == null && p1.getSortText() == null) return 0; + if(p1.getSortText() == null && p2.getSortText() != null) return -1; + if(p1.getSortText() != null && p2.getSortText() == null) return 1; + if(p1.getSortText() == null && p2.getSortText() == null) return 0; return p1.getSortText().compareTo(p2.getSortText()); } }; - private CompletableFuture, CompletionList>> lastRequest; - - /** - * TODO: Change this to a language server implementation and remove the use of passing editor content - */ @Override - public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { - final IDELanguageServer server = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_XML); - if(server == null) - return List.of(); - - if(lastRequest != null && !lastRequest.isDone()) { - lastRequest.cancel(true); - } - - final CompletionParams params = new CompletionParams(); - params.setTextDocument(new TextDocumentIdentifier(fileUri)); - params.setPosition(new Position(line, column)); - - lastRequest = server.getTextDocumentService().completion(params); - - try { - Either, CompletionList> result = lastRequest.get(); - if(result != null) { - if(result.isLeft()) { - return sort(result.getLeft()); - } else if(result.isRight()) { - return sort(result.getRight().getItems()); - } - } - } catch (Throwable th) { - LOG.error("XML Completion error", th); - return List.of(); - } - - return List.of(); + public List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { + final XMLCompletionService service = StudioApp.getInstance().getXmlCompletionService(); + return sort(service.complete(content, index, line, column, prefix.toLowerCase().trim())); } private List sort(List result) { diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java index 94eb0c99b..23f6432cf 100644 --- a/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java @@ -14,13 +14,14 @@ import java.io.File; import java.io.StringReader; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Token; +import com.itsaky.androidide.lsp.LanguageServerWrapper; public class XMLLanguage extends BaseLanguage { private XMLAnalyzer analyzer; private XMLAutoComplete completer; private NewlineHandler[] newlineHandlers = new NewlineHandler[] {}; - + public XMLLanguage() { super(null); } @@ -34,7 +35,7 @@ public class XMLLanguage extends BaseLanguage { @Override public IDELanguageServer getLanguageServer() { - return LSPProvider.getServerForLanguage(getLanguageCode()); + return null; } @Override diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java b/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java index eae0f2b53..a19803bd4 100644 --- a/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/completion/XMLCompletionService.java @@ -3,7 +3,6 @@ package com.itsaky.androidide.language.xml.completion; import com.itsaky.androidide.language.xml.lexer.XMLLexer; import com.itsaky.androidide.utils.Environment; import com.itsaky.androidide.utils.FileUtil; -import io.github.rosemoe.editor.widget.CodeEditor; import java.io.File; import java.io.StringReader; import java.util.ArrayList; @@ -17,16 +16,16 @@ import java.util.Set; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Token; import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.InsertTextFormat; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import org.eclipse.lsp4j.InsertTextFormat; -import org.eclipse.lsp4j.CompletionItemKind; public class XMLCompletionService { private HashMap attrs; - private List widgets; + private List widgets; private final File ANDROID_ATTRS; private final File ANDROID_WIDGETS; @@ -37,6 +36,7 @@ public class XMLCompletionService { this.ANDROID_WIDGETS = new File(Environment.BOOTCLASSPATH.getParentFile(), "data/widgets.txt"); this.attrs = new HashMap<>(); this.widgets = new ArrayList<>(); + if(ANDROID_ATTRS.exists() && ANDROID_ATTRS.isFile()) { addAttributesFrom(ANDROID_ATTRS, true); } @@ -51,8 +51,7 @@ public class XMLCompletionService { return initiated; } - - public List complete(int index, int line, int column, String prefix) { + public List complete(CharSequence content, int index, int line, int column, String prefix) { final List result = new ArrayList<>(); if(prefix.startsWith("<") || prefix.startsWith("' + // They may have been already inserted by editor upon typing '<' + + sb.append(view.simpleName); + + if(!closing) { + if(view.isViewGroup) { + sb.append(">$0$0"); + } + + return sb.toString(); + } private String simpleName(String name) { return name.substring(name.lastIndexOf(".") + 1); @@ -142,9 +177,19 @@ public class XMLCompletionService { if(read != null && read.length() > 0) { widgets.clear(); for(String line : read.split("\\n")) { - String name = line.split("\\s")[0]; - name = name.substring(1); - widgets.add(name); + final String name = line.split("\\s")[0]; + if(name == null || name.trim().isEmpty()) continue; + + final char code = name.charAt(0); + + final String viewName = name.substring(1); + final String simpleViewName = simpleName(viewName); + final boolean isViewGroup = code == 'L'; // L -> Layout, W -> Widget, P -> LayoutParam + + // Don't add layout params + if(code != 'P') { + widgets.add(new Widget(viewName, simpleViewName, isViewGroup)); + } } Collections.sort(widgets); } @@ -199,9 +244,9 @@ public class XMLCompletionService { return start <= cursorIndex && cursorIndex <= end; } - public String scan(String xmlContent) { + public String scan(CharSequence xmlContent) { try { - XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(xmlContent))); + XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(xmlContent.toString()))); Token token; String attrName = null; while((token = lexer.nextToken()) != null && token.getType() != XMLLexer.EOF) { @@ -219,7 +264,7 @@ public class XMLCompletionService { } - private class Attr { + class Attr { public String prefix; public String name; @@ -240,4 +285,25 @@ public class XMLCompletionService { return String.format("[%s=%s]", name, possibleValues.toString()); } } + + class Widget implements Comparable { + String name; + String simpleName; + boolean isViewGroup; + + public Widget(String name, String simpleName, boolean isViewGroup) { + this.name = name; + this.simpleName = simpleName; + this.isViewGroup = isViewGroup; + } + + @Override + public int compareTo(Object p1) { + if(p1 instanceof Widget) { + final Widget that = (Widget) p1; + return this.simpleName.compareTo(that.simpleName); + } + return -1; + } + } } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/LSP.java b/app/src/main/java/com/itsaky/androidide/lsp/LSP.java index a047b1914..06d8aa6cc 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/LSP.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/LSP.java @@ -2,8 +2,6 @@ package com.itsaky.androidide.lsp; import com.itsaky.androidide.interfaces.EditorActivityProvider; import com.itsaky.androidide.lsp.handlers.JLSHandler; -import com.itsaky.androidide.lsp.handlers.LSPHandler; -import com.itsaky.androidide.lsp.handlers.XMLLanguageServerHandler; import com.itsaky.androidide.utils.Logger; import com.itsaky.lsp.services.IDELanguageServer; import java.io.File; @@ -40,13 +38,7 @@ public class LSP { public static EditorActivityProvider PROVIDER; private static final Logger LOG = Logger.instance("LSP"); - public static LSPHandler Java = new JLSHandler(); - public static LSPHandler XML = new XMLLanguageServerHandler(); - - public static void startAll(Runnable onStarted) { - LSP.Java.start(onStarted); - LSP.XML.start(onStarted); - } + public static JLSHandler Java = new JLSHandler(); /** * Stores information about ports at which the specified language server must be started @@ -142,7 +134,6 @@ public class LSP { public static void shutdownAll() { // Shutdown language servers one by one LSP.Java.shutdown(); - LSP.XML.shutdown(); } /** diff --git a/app/src/main/java/com/itsaky/androidide/lsp/client/xml/XMLLanguageClient.java b/app/src/main/java/com/itsaky/androidide/lsp/client/xml/XMLLanguageClient.java deleted file mode 100644 index 9b927d3fa..000000000 --- a/app/src/main/java/com/itsaky/androidide/lsp/client/xml/XMLLanguageClient.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.itsaky.androidide.lsp.client.xml; - -import com.itsaky.androidide.lsp.AbstractLanguageClient; -import com.itsaky.androidide.utils.JSONUtility; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.eclipse.lemminx.customservice.ActionableNotification; -import org.eclipse.lemminx.customservice.XMLLanguageClientAPI; -import org.eclipse.lsp4j.ApplyWorkspaceEditParams; -import org.eclipse.lsp4j.ApplyWorkspaceEditResponse; -import org.eclipse.lsp4j.ConfigurationParams; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.MessageActionItem; -import org.eclipse.lsp4j.MessageParams; -import org.eclipse.lsp4j.ProgressParams; -import org.eclipse.lsp4j.RegistrationParams; -import org.eclipse.lsp4j.SetTraceParams; -import org.eclipse.lsp4j.ShowMessageRequestParams; -import org.eclipse.lsp4j.UnregistrationParams; -import org.eclipse.lsp4j.WorkDoneProgressCreateParams; -import org.eclipse.lsp4j.WorkspaceFolder; - -public class XMLLanguageClient extends AbstractLanguageClient implements XMLLanguageClientAPI { - - public XMLLanguageClient(StarterListener starterListener, OnConnectedListener onConnectedListener) { - super(starterListener, onConnectedListener); - } - - @Override - public void actionableNotification(ActionableNotification p1) { - LOG.info("XMLLS: actionableNotification: " + JSONUtility.prettyPrinter.toJson(p1)); - } - - @Override - public CompletableFuture executeClientCommand(ExecuteCommandParams p1) { - LOG.info("XMLLS: executeClientCommand: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public CompletableFuture applyEdit(ApplyWorkspaceEditParams p1) { - LOG.info("XMLLS: applyEdit: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public CompletableFuture> configuration(ConfigurationParams p1) { - LOG.info("XMLLS: configuration: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public CompletableFuture createProgress(WorkDoneProgressCreateParams p1) { - LOG.info("XMLLS: createProgress: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public void notifyProgress(ProgressParams p1) { - LOG.info("XMLLS: notifyProgress: ", gson.toJson(p1)); - } - - @Override - public CompletableFuture refreshCodeLenses() { - LOG.info("XMLLS: refreshCodeLenses"); - return null; - } - - @Override - public CompletableFuture refreshSemanticTokens() { - LOG.info("XMLLS: refreshSemanticTokens: "); - return null; - } - - @Override - public CompletableFuture registerCapability(RegistrationParams p1) { - LOG.info("XMLLS: registerCapability: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public void setTrace(SetTraceParams p1) { - LOG.info("XMLLS: setTrafe: " + JSONUtility.prettyPrinter.toJson(p1)); - } - - @Override - public void showMessage(MessageParams p1) { - LOG.info("XMLLS: showMessage: " + JSONUtility.prettyPrinter.toJson(p1)); - } - - @Override - public CompletableFuture showMessageRequest(ShowMessageRequestParams p1) { - LOG.info("XMLLS: showMessageRequest: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public CompletableFuture unregisterCapability(UnregistrationParams p1) { - LOG.info("XMLLS: unregisterCapability: " + JSONUtility.prettyPrinter.toJson(p1)); - return null; - } - - @Override - public CompletableFuture> workspaceFolders() { - LOG.info("XMLLS: workspaceFolders"); - return null; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/lsp/handlers/LSPHandler.java b/app/src/main/java/com/itsaky/androidide/lsp/handlers/LSPHandler.java index 1fa5b185e..16eb4c6d3 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/handlers/LSPHandler.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/handlers/LSPHandler.java @@ -1,4 +1,5 @@ package com.itsaky.androidide.lsp.handlers; + import java.util.Optional; import org.eclipse.lsp4j.InitializeResult; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/handlers/XMLLanguageServerHandler.java b/app/src/main/java/com/itsaky/androidide/lsp/handlers/XMLLanguageServerHandler.java deleted file mode 100644 index 7ff4a2446..000000000 --- a/app/src/main/java/com/itsaky/androidide/lsp/handlers/XMLLanguageServerHandler.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.itsaky.androidide.lsp.handlers; - -import com.itsaky.androidide.lsp.LSP; -import com.itsaky.androidide.lsp.LSPProvider; -import com.itsaky.androidide.lsp.LanguageServerWrapper; -import com.itsaky.androidide.lsp.client.xml.XMLLanguageClient; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import org.eclipse.lemminx.XMLLanguageServer; -import org.eclipse.lsp4j.InitializeParams; -import org.eclipse.lsp4j.InitializeResult; -import org.eclipse.lsp4j.InitializedParams; -import org.eclipse.lsp4j.WorkspaceFolder; - -public class XMLLanguageServerHandler implements LSPHandler { - - private LanguageServerWrapper server; - private XMLLanguageClient client; - - @Override - public void start(Runnable onStarted) { - server = new LanguageServerWrapper(new XMLLanguageServer()); - client = new XMLLanguageClient(null, null); - ((XMLLanguageServer) server.getServer()).setClient(client); - - LSPProvider.setLanguageServer(LSPProvider.LANGUAGE_XML, server); - LSPProvider.setClientForLanguage(LSPProvider.LANGUAGE_XML, client); - - if(onStarted != null) - onStarted.run(); - } - - @Override - public Optional init(String rootPath) { - - if(this.server == null) { - return Optional.empty(); - } - - final List folders = new ArrayList<>(); - final File file = new File(rootPath); - final WorkspaceFolder folder = new WorkspaceFolder(); - - folder.setUri(file.toURI().toString()); - folder.setName(file.getName().toString()); - folders.add(folder); - - InitializeParams params = new InitializeParams(); - params.setClientInfo(LSP.getClientInfo()); - params.setWorkspaceFolders(folders); - params.setCapabilities(LSP.getCapabilities()); - - CompletableFuture initResult = server.initialize(params); - try { - InitializeResult result = initResult.get(); - if(result.getCapabilities() != null) { - LSPProvider.setServerCapabilitesForLanguage(LSPProvider.LANGUAGE_XML, result.getCapabilities()); - } - return Optional.of(result); - } catch (Throwable e) { - return Optional.empty(); - } - } - - @Override - public void initialized() { - - if(server == null) - return; - - server.initialized(new InitializedParams()); - - } - - @Override - public void shutdown() { - server.shutdown(); - } -} diff --git a/app/src/main/java/io/github/rosemoe/editor/interfaces/AutoCompleteProvider.java b/app/src/main/java/io/github/rosemoe/editor/interfaces/AutoCompleteProvider.java index a13ff2250..4aec95e95 100644 --- a/app/src/main/java/io/github/rosemoe/editor/interfaces/AutoCompleteProvider.java +++ b/app/src/main/java/io/github/rosemoe/editor/interfaces/AutoCompleteProvider.java @@ -37,7 +37,7 @@ public interface AutoCompleteProvider { * @param line The line of cursor * @return Analyzed items */ - List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception; + List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception; } diff --git a/app/src/main/java/io/github/rosemoe/editor/langs/EmptyLanguage.java b/app/src/main/java/io/github/rosemoe/editor/langs/EmptyLanguage.java index 04a0f2ec4..c7134f8be 100644 --- a/app/src/main/java/io/github/rosemoe/editor/langs/EmptyLanguage.java +++ b/app/src/main/java/io/github/rosemoe/editor/langs/EmptyLanguage.java @@ -89,7 +89,7 @@ public class EmptyLanguage extends AbstractEditorLanguage { public static class EmptyAutoCompleteProvider implements AutoCompleteProvider { @Override - public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { + public List getAutoCompleteItems(CharSequence content, String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) { return new ArrayList(); } diff --git a/app/src/main/java/io/github/rosemoe/editor/widget/EditorAutoCompleteWindow.java b/app/src/main/java/io/github/rosemoe/editor/widget/EditorAutoCompleteWindow.java index 4a1a64fdb..e7f2e1221 100644 --- a/app/src/main/java/io/github/rosemoe/editor/widget/EditorAutoCompleteWindow.java +++ b/app/src/main/java/io/github/rosemoe/editor/widget/EditorAutoCompleteWindow.java @@ -39,6 +39,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.Command; +import io.github.rosemoe.editor.text.ContentLine; public class EditorAutoCompleteWindow extends EditorBasePopupWindow { private final static String TIP = "Refreshing..."; @@ -187,12 +188,11 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { * @param pos Index of auto complete item */ public void select(int pos) { - CompletionItem item = ((EditorCompletionAdapter) mBinding.list.getAdapter()).getItem(pos); - Range range = getIdentifierRange(mEditor.getCursor().getRight(), mEditor.getText()); + final CompletionItem item = ((EditorCompletionAdapter) mBinding.list.getAdapter()).getItem(pos); + final Range range = getIdentifierRange(mEditor.getCursor().getRight(), mEditor.getText()); + String text = item.getInsertText() == null ? item.getLabel() : item.getInsertText(); - final boolean shiftLeft = text.contains("$0"); - final boolean atEnd = text.endsWith("$0"); - text = text.replace("$0", ""); + final boolean shiftCursor = item.getInsertText() != null && text.contains("$0"); mEditor.getText().delete( range.getStart().getLine(), @@ -202,8 +202,14 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { ); mEditor.getCursor().onCommitText(text); - if(shiftLeft && !atEnd) { - mEditor.moveSelectionLeft(); + if(shiftCursor) { + final int line = mEditor.getCursor().getLeftLine(); + final String lineText = mEditor.getText().getLineString(line); + final int column = lineText.lastIndexOf("$0"); + if(column != -1){ + mEditor.setSelection(line, column); + mEditor.getText().delete(line, column, line, column + 2); + } } final List edits = item.getAdditionalTextEdits(); @@ -226,7 +232,7 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { Command cmd = item.getCommand(); if("editor.action.triggerParameterHints".equals(cmd.getCommand())) { - // Trigger signature help request included in CompletionItem + // Trigger signature help request if included in CompletionItem // TODO Don't rely on CompletionItem for requesting signature help // If the insert text contains '(', automatically trigger this action mEditor.signatureHelp("("); @@ -308,6 +314,7 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { private final long mTime; private final String mPrefix; private final String mFileUri; + private final CharSequence mContent; private final boolean mInner; private final TextAnalyzeResult mColors; private final int mIndex; @@ -319,6 +326,7 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { mTime = requestTime; mPrefix = prefix; mFileUri = mEditor.getFile() != null ? mEditor.getFile().toURI().toString() : null; + mContent = mEditor.getText(); mColors = mEditor.getTextAnalyzeResult(); mIndex = mEditor.getCursor().getLeft(); mLine = mEditor.getCursor().getLeftLine(); @@ -329,7 +337,7 @@ public class EditorAutoCompleteWindow extends EditorBasePopupWindow { @Override public void run() { try { - displayResults(mLocalProvider.getAutoCompleteItems(mFileUri, mPrefix, mInner, mColors, mIndex, mLine, mColumn), mTime); + displayResults(mLocalProvider.getAutoCompleteItems(mContent, mFileUri, mPrefix, mInner, mColors, mIndex, mLine, mColumn), mTime); } catch (Exception e) { e.printStackTrace(); displayResults(new ArrayList<>(), mTime); diff --git a/build.gradle b/build.gradle index ef546c237..2d8c5f6d0 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,8 @@ buildscript { javaSourceVersion = JavaVersion.VERSION_1_8 javaTargetVersion = JavaVersion.VERSION_1_8 + + stringfogEnabled = false } repositories { diff --git a/gradle.properties b/gradle.properties index 44179d20b..09bcc9c74 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx700m +org.gradle.jvmargs=-Xmx512m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/lemminx/src/main/AndroidManifest.xml b/lemminx/src/main/AndroidManifest.xml deleted file mode 100644 index 95086d380..000000000 --- a/lemminx/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lemminx/src/main/java/org/eclipse/lemminx/NoOpInputStream.java b/lemminx/src/main/java/org/eclipse/lemminx/NoOpInputStream.java deleted file mode 100644 index 2e7164dbd..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/NoOpInputStream.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx; - -import java.io.IOException; -import java.io.InputStream; - -/** - * No-Op {@link InputStream} - * - * @author Fred Bricon - */ -class NoOpInputStream extends InputStream { - - @Override - public int read() throws IOException { - return -1; - } - - @Override - public int read(byte[] b) throws IOException { - return -1; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - return -1; - } - - @Override - public int available() throws IOException { - return 0; - } - - @Override - public synchronized void mark(int readlimit) { - } - - @Override - public boolean markSupported() { - return true; - } - - @Override - public synchronized void reset() throws IOException { - } - - @Override - public long skip(long n) throws IOException { - return 0; - } - - @Override - public void close() throws IOException { - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/NoOpOutputStream.java b/lemminx/src/main/java/org/eclipse/lemminx/NoOpOutputStream.java deleted file mode 100644 index 8da85adba..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/NoOpOutputStream.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * No-Op {@link OutputStream}. - * - * @author Fred Bricon - */ -class NoOpOutputStream extends OutputStream { - - @Override - public void write(int b) throws IOException { - } - - @Override - public void write(byte[] b, int off, int len) { - } - - @Override - public void write(byte[] b) throws IOException { - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/NoOpPrintStream.java b/lemminx/src/main/java/org/eclipse/lemminx/NoOpPrintStream.java deleted file mode 100644 index f50cee3c2..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/NoOpPrintStream.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx; - -import java.io.PrintStream; - -/** - * No-Op {@link PrintStream}. - * - * @author Fred Bricon - */ -class NoOpPrintStream extends PrintStream { - - public NoOpPrintStream() { - super(new NoOpOutputStream()); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/XMLLanguageServer.java b/lemminx/src/main/java/org/eclipse/lemminx/XMLLanguageServer.java deleted file mode 100644 index 068ccebba..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/XMLLanguageServer.java +++ /dev/null @@ -1,349 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - * Red Hat Inc. - Dynamic Server capabilities - */ -package org.eclipse.lemminx; - -import static org.eclipse.lsp4j.jsonrpc.CompletableFutures.computeAsync; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.client.ExtendedClientCapabilities; -import org.eclipse.lemminx.commons.ModelTextDocument; -import org.eclipse.lemminx.commons.ParentProcessWatcher.ProcessLanguageServer; -import org.eclipse.lemminx.customservice.ActionableNotification; -import org.eclipse.lemminx.customservice.AutoCloseTagResponse; -import org.eclipse.lemminx.customservice.XMLLanguageClientAPI; -import org.eclipse.lemminx.customservice.XMLLanguageServerAPI; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.extensions.contentmodel.settings.ContentModelSettings; -import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; -import org.eclipse.lemminx.logs.LogHelper; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.IXMLNotificationService; -import org.eclipse.lemminx.services.IXMLValidationService; -import org.eclipse.lemminx.services.XMLLanguageService; -import org.eclipse.lemminx.settings.AllXMLSettings; -import org.eclipse.lemminx.settings.InitializationOptionsSettings; -import org.eclipse.lemminx.settings.ServerSettings; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lemminx.settings.XMLCodeLensSettings; -import org.eclipse.lemminx.settings.XMLCompletionSettings; -import org.eclipse.lemminx.settings.XMLFormattingOptions; -import org.eclipse.lemminx.settings.XMLGeneralClientSettings; -import org.eclipse.lemminx.settings.XMLPreferences; -import org.eclipse.lemminx.settings.XMLSymbolSettings; -import org.eclipse.lemminx.settings.XMLTelemetrySettings; -import org.eclipse.lemminx.settings.capabilities.InitializationOptionsExtendedClientCapabilities; -import org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesInitializer; -import org.eclipse.lemminx.settings.capabilities.XMLCapabilityManager; -import org.eclipse.lemminx.telemetry.TelemetryManager; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lemminx.utils.platform.Platform; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.InitializeParams; -import org.eclipse.lsp4j.InitializeResult; -import org.eclipse.lsp4j.InitializedParams; -import org.eclipse.lsp4j.MessageParams; -import org.eclipse.lsp4j.MessageType; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.ServerCapabilities; -import org.eclipse.lsp4j.TextDocumentPositionParams; -import org.eclipse.lsp4j.services.LanguageClient; -import org.eclipse.lsp4j.services.TextDocumentService; -import org.eclipse.lsp4j.services.WorkspaceService; - -/** - * XML language server. - * - */ -public class XMLLanguageServer - implements ProcessLanguageServer, XMLLanguageServerAPI, IXMLDocumentProvider, - IXMLNotificationService, IXMLValidationService { - - private static final Logger LOGGER = Logger.getLogger(XMLLanguageServer.class.getName()); - - private final XMLLanguageService xmlLanguageService; - private final XMLTextDocumentService xmlTextDocumentService; - private final XMLWorkspaceService xmlWorkspaceService; - private XMLLanguageClientAPI languageClient; - private final ScheduledExecutorService delayer; - private Integer parentProcessId; - private XMLCapabilityManager capabilityManager; - private TelemetryManager telemetryManager; - - public XMLLanguageServer() { - xmlTextDocumentService = new XMLTextDocumentService(this); - xmlWorkspaceService = new XMLWorkspaceService(this); - - xmlLanguageService = new XMLLanguageService(); - xmlLanguageService.setDocumentProvider(this); - xmlLanguageService.setNotificationService(this); - xmlLanguageService.setCommandService(xmlWorkspaceService); - xmlLanguageService.setValidationService(this); - - delayer = Executors.newScheduledThreadPool(1); - } - - @Override - public CompletableFuture initialize(InitializeParams params) { - Object initOptions = InitializationOptionsSettings.getSettings(params); - Object xmlSettings = AllXMLSettings.getAllXMLSettings(initOptions); - XMLGeneralClientSettings settings = XMLGeneralClientSettings.getGeneralXMLSettings(xmlSettings); - - LogHelper.initializeRootLogger(languageClient, settings == null? null : settings.getLogs()); - - LOGGER.info("Initializing XML Language server" + System.lineSeparator() + Platform.details()); - - this.parentProcessId = params.getProcessId(); - - xmlLanguageService.setTelemetryManager(getTelemetryManager()); - // Update XML language service extensions with InitializeParams - xmlLanguageService.initializeParams(params); - - ExtendedClientCapabilities extendedClientCapabilities = InitializationOptionsExtendedClientCapabilities - .getExtendedClientCapabilities(params); - capabilityManager.setClientCapabilities(params.getCapabilities(), extendedClientCapabilities); - - xmlTextDocumentService.updateClientCapabilities(capabilityManager.getClientCapabilities().capabilities, - capabilityManager.getClientCapabilities().getExtendedCapabilities()); - - updateSettings(initOptions, false /* already configured logging*/ ); - - ServerCapabilities nonDynamicServerCapabilities = ServerCapabilitiesInitializer.getNonDynamicServerCapabilities( - capabilityManager.getClientCapabilities(), xmlTextDocumentService.isIncrementalSupport()); - - return CompletableFuture.completedFuture(new InitializeResult(nonDynamicServerCapabilities)); - } - - /* - * Registers all capabilities that do not support client side preferences to - * turn on/off - * - * (non-Javadoc) - * - * @see org.eclipse.lsp4j.services.LanguageServer#initialized(org.eclipse.lsp4j. - * InitializedParams) - */ - @Override - public void initialized(InitializedParams params) { - capabilityManager.initializeCapabilities(); - getTelemetryManager().onInitialized(params); - } - - /** - * Update XML settings configured from the client. - * - * @param initOptions the XML settings - */ - public synchronized void updateSettings(Object initOptions) { - updateSettings(initOptions, true); - } - - /** - * Update XML settings configured from the client. - * - * @param initOptions Settings the XML settings - * @param initLogs whether to initialize the log handlers - */ - private synchronized void updateSettings(Object initOptions, boolean initLogs) { - if (initOptions == null) { - return; - } - // Update client settings - Object initSettings = AllXMLSettings.getAllXMLSettings(initOptions); - XMLGeneralClientSettings xmlClientSettings = XMLGeneralClientSettings.getGeneralXMLSettings(initSettings); - if (xmlClientSettings != null) { - if (initLogs) { - // Update logs settings - LogHelper.initializeRootLogger(languageClient, xmlClientSettings.getLogs()); - } - - XMLTelemetrySettings newTelemetry = xmlClientSettings.getTelemetry(); - if (newTelemetry != null) { - getTelemetryManager().setEnabled(newTelemetry.isEnabled()); - } - - // Update format settings - XMLFormattingOptions formatterSettings = xmlClientSettings.getFormat(); - if (formatterSettings != null) { - xmlTextDocumentService.getSharedFormattingSettings().merge(formatterSettings); - } - - XMLCompletionSettings newCompletions = xmlClientSettings.getCompletion(); - if (newCompletions != null) { - xmlTextDocumentService.updateCompletionSettings(newCompletions); - } - - XMLSymbolSettings newSymbols = xmlClientSettings.getSymbols(); - if (newSymbols != null) { - xmlTextDocumentService.updateSymbolSettings(newSymbols); - } - - XMLCodeLensSettings newCodeLens = xmlClientSettings.getCodeLens(); - if (newCodeLens != null) { - xmlTextDocumentService.updateCodeLensSettings(newCodeLens); - } - - XMLPreferences newPreferences = xmlClientSettings.getPreferences(); - if (newPreferences != null) { - xmlTextDocumentService.updatePreferences(newPreferences); - } - - ServerSettings serverSettings = xmlClientSettings.getServer(); - if (serverSettings != null) { - String workDir = serverSettings.getNormalizedWorkDir(); - FilesUtils.setCachePathSetting(workDir); - } - } - ContentModelSettings cmSettings = ContentModelSettings.getContentModelXMLSettings(initSettings); - if (cmSettings != null) { - XMLValidationSettings validationSettings = cmSettings.getValidation(); - xmlTextDocumentService.getValidationSettings().merge(validationSettings); - - } - // Update XML language service extensions - xmlTextDocumentService.updateSettings(initSettings); - } - - @Override - public CompletableFuture shutdown() { - xmlLanguageService.dispose(); - if (capabilityManager.getClientCapabilities().getExtendedCapabilities().shouldLanguageServerExitOnShutdown()) { - delayer.schedule(() -> exit(0) , 1, TimeUnit.SECONDS); - } - return computeAsync(cc -> new Object()); - } - - @Override - public void exit() { - exit(0); - } - - @Override - public void exit(int exitCode) { - delayer.shutdown(); - System.exit(exitCode); - } - - @Override - public TextDocumentService getTextDocumentService() { - return xmlTextDocumentService; - } - - @Override - public WorkspaceService getWorkspaceService() { - return xmlWorkspaceService; - } - - public void setClient(LanguageClient languageClient) { - this.languageClient = (XMLLanguageClientAPI) languageClient; - capabilityManager = new XMLCapabilityManager(this.languageClient, xmlTextDocumentService); - telemetryManager = new TelemetryManager(languageClient); - } - - public XMLLanguageClientAPI getLanguageClient() { - return languageClient; - } - - public XMLLanguageService getXMLLanguageService() { - return xmlLanguageService; - } - - public SharedSettings getSettings() { - return xmlTextDocumentService.getSharedSettings(); - } - - public ScheduledFuture schedule(Runnable command, int delay, TimeUnit unit) { - return delayer.schedule(command, delay, unit); - } - - @Override - public long getParentProcessId() { - return parentProcessId != null ? parentProcessId : 0; - } - - @Override - public CompletableFuture closeTag(TextDocumentPositionParams params) { - return xmlTextDocumentService.computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().doAutoClose(xmlDocument, params.getPosition(), getSettings().getCompletionSettings(), cancelChecker); - }); - } - - @Override - public CompletableFuture matchingTagPosition(TextDocumentPositionParams params) { - return xmlTextDocumentService.computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().getMatchingTagPosition(xmlDocument, params.getPosition(), cancelChecker); - }); - } - - @Override - public DOMDocument getDocument(String uri) { - ModelTextDocument document = xmlTextDocumentService.getDocument(uri); - return document != null ? document.getModel().getNow(null) : null; - } - - @Override - public void sendNotification(String message, MessageType messageType, Command... commands) { - SharedSettings sharedSettings = getSharedSettings(); - if (sharedSettings.isActionableNotificationSupport() && sharedSettings.isOpenSettingsCommandSupport()) { - ActionableNotification notification = new ActionableNotification().withSeverity(messageType) - .withMessage(message).withCommands(Arrays.asList(commands)); - languageClient.actionableNotification(notification); - } else { - // the open settings command is not supported by the client, display a simple - // message with LSP - languageClient.showMessage(new MessageParams(messageType, message)); - } - } - - @Override - public SharedSettings getSharedSettings() { - return xmlTextDocumentService.getSharedSettings(); - } - - @Override - public Collection getAllDocuments() { - return xmlTextDocumentService.allDocuments().stream() - .map(m -> m.getModel().getNow(null)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - @Override - public void validate(DOMDocument document) { - xmlTextDocumentService.validate(document); - } - - public XMLCapabilityManager getCapabilityManager() { - return capabilityManager; - } - - /** - * Returns the telemetry manager. - * - * @return the telemetry manager. - */ - public TelemetryManager getTelemetryManager() { - return telemetryManager; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/XMLServerLauncher.java b/lemminx/src/main/java/org/eclipse/lemminx/XMLServerLauncher.java deleted file mode 100644 index d05969791..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/XMLServerLauncher.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.Authenticator; -import java.net.PasswordAuthentication; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.function.Function; - -import org.eclipse.lemminx.commons.ParentProcessWatcher; -import org.eclipse.lemminx.customservice.XMLLanguageClientAPI; -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.jsonrpc.MessageConsumer; -import org.eclipse.lsp4j.launch.LSPLauncher.Builder; -import org.eclipse.lsp4j.services.LanguageClient; -import org.eclipse.lsp4j.services.LanguageServer; - -public class XMLServerLauncher { - - /** - * Calls {@link #launch(InputStream, OutputStream)}, using the standard input - * and output streams. - */ - public static void main(String[] args) { - - final String HTTP_PROXY_HOST = System.getenv("HTTP_PROXY_HOST"); - final String HTTP_PROXY_PORT = System.getenv("HTTP_PROXY_PORT"); - final String HTTP_PROXY_USERNAME = System.getenv("HTTP_PROXY_USERNAME"); - final String HTTP_PROXY_PASSWORD = System.getenv("HTTP_PROXY_PASSWORD"); - final boolean LEMMINX_DEBUG = System.getenv("LEMMINX_DEBUG") != null; - - if (HTTP_PROXY_HOST != null && HTTP_PROXY_PORT != null) { - System.setProperty("http.proxyHost", HTTP_PROXY_HOST); - System.setProperty("http.proxyPort", HTTP_PROXY_PORT); - } - - if (HTTP_PROXY_USERNAME != null && HTTP_PROXY_PASSWORD != null) { - System.setProperty("http.proxyUser", HTTP_PROXY_USERNAME); - System.setProperty("http.proxyPassword", HTTP_PROXY_PASSWORD); - } - - final String username = System.getProperty("http.proxyUser"); - final String password = System.getProperty("http.proxyPassword"); - - if (username != null && password != null) { - Authenticator.setDefault(new Authenticator() { - - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password.toCharArray()); - } - - }); - } - InputStream in = System.in; - PrintStream out = System.out; - System.setIn(new NoOpInputStream()); - System.setOut(new NoOpPrintStream()); - if (!LEMMINX_DEBUG) { - System.setErr(new NoOpPrintStream()); - } - launch(in, out); - } - - /** - * Launches {@link XMLLanguageServer} and makes it accessible through the JSON - * RPC protocol defined by the LSP. - * - * @param launcherFuture The future returned by - * {@link org.eclipse.lsp4j.jsonrpc.Launcher#startListening()}. - * (I'm not 100% sure how it meant to be used though, as - * it's undocumented...) - */ - public static Future launch(InputStream in, OutputStream out) { - XMLLanguageServer server = new XMLLanguageServer(); - Function wrapper; - if ("false".equals(System.getProperty("watchParentProcess"))) { - wrapper = it -> it; - } else { - wrapper = new ParentProcessWatcher(server); - } - Launcher launcher = createServerLauncher(server, in, out, Executors.newCachedThreadPool(), wrapper); - server.setClient(launcher.getRemoteProxy()); - return launcher.startListening(); - } - - /** - * Create a new Launcher for a language server and an input and output stream. - * Threads are started with the given executor service. The wrapper function is - * applied to the incoming and outgoing message streams so additional message - * handling such as validation and tracing can be included. - * - * @param server - the server that receives method calls from the - * remote client - * @param in - input stream to listen for incoming messages - * @param out - output stream to send outgoing messages - * @param executorService - the executor service used to start threads - * @param wrapper - a function for plugging in additional message - * consumers - */ - private static Launcher createServerLauncher(LanguageServer server, InputStream in, OutputStream out, - ExecutorService executorService, Function wrapper) { - return new Builder(). - setLocalService(server) - .setRemoteInterface(XMLLanguageClientAPI.class) // Set client as XML language client - .setInput(in) - .setOutput(out) - .setExecutorService(executorService) - .wrapMessages(wrapper) - .create(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/XMLServerSocketLauncher.java b/lemminx/src/main/java/org/eclipse/lemminx/XMLServerSocketLauncher.java deleted file mode 100644 index 2c1b52461..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/XMLServerSocketLauncher.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2018 TypeFox GmbH (http://www.typefox.io) and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * @author Dennis Huebner - Initial contribution and API - */ -package org.eclipse.lemminx; - -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.nio.channels.AsynchronousServerSocketChannel; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.Channels; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.jsonrpc.MessageConsumer; -import org.eclipse.lsp4j.services.LanguageClient; - -public class XMLServerSocketLauncher { - - private static final int DEFAULT_PORT = 5_008; - - /** - * Calls {@link #launch(String[])} - */ - public static void main(String[] args) throws Exception { - new XMLServerSocketLauncher().launch(args); - } - - /** - * Launches {@link XMLLanguageServer} using asynchronous server-socket channel and makes it accessible through the JSON - * RPC protocol defined by the LSP. - * - * @param args standard launch arguments. may contain --port argument to change the default port 5008 - */ - public void launch(String[] args) throws Exception { - AsynchronousServerSocketChannel _open = AsynchronousServerSocketChannel.open(); - int _port = getPort(args); - InetSocketAddress _inetSocketAddress = new InetSocketAddress("0.0.0.0", _port); - final AsynchronousServerSocketChannel serverSocket = _open.bind(_inetSocketAddress); - while (true) { - final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); - final InputStream in = Channels.newInputStream(socketChannel); - final OutputStream out = Channels.newOutputStream(socketChannel); - final ExecutorService executorService = Executors.newCachedThreadPool(); - XMLLanguageServer languageServer = new XMLLanguageServer(); - final Launcher launcher = Launcher.createIoLauncher(languageServer, LanguageClient.class, - in, out, executorService, (MessageConsumer it) -> { - return it; - }); - languageServer.setClient(launcher.getRemoteProxy()); - launcher.startListening(); - } - } - - protected int getPort(final String... args) { - for (int i = 0; (i < (args.length - 1)); i++) { - String _get = args[i]; - boolean _equals = Objects.equals(_get, "--port"); - if (_equals) { - return Integer.parseInt(args[(i + 1)]); - } - } - return DEFAULT_PORT; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/XMLTextDocumentService.java b/lemminx/src/main/java/org/eclipse/lemminx/XMLTextDocumentService.java deleted file mode 100644 index 6575a40ee..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/XMLTextDocumentService.java +++ /dev/null @@ -1,733 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx; - -import static org.eclipse.lsp4j.jsonrpc.CompletableFutures.computeAsync; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.function.BiFunction; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.client.ExtendedClientCapabilities; -import org.eclipse.lemminx.client.LimitExceededWarner; -import org.eclipse.lemminx.client.LimitFeature; -import org.eclipse.lemminx.commons.ModelTextDocument; -import org.eclipse.lemminx.commons.ModelTextDocuments; -import org.eclipse.lemminx.commons.TextDocument; -import org.eclipse.lemminx.commons.TextDocuments; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.dom.DOMParser; -import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; -import org.eclipse.lemminx.services.DocumentSymbolsResult; -import org.eclipse.lemminx.services.SymbolInformationResult; -import org.eclipse.lemminx.services.XMLLanguageService; -import org.eclipse.lemminx.services.extensions.save.AbstractSaveContext; -import org.eclipse.lemminx.settings.CompositeSettings; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lemminx.settings.XMLCodeLensSettings; -import org.eclipse.lemminx.settings.XMLCompletionSettings; -import org.eclipse.lemminx.settings.XMLFormattingOptions; -import org.eclipse.lemminx.settings.XMLPreferences; -import org.eclipse.lemminx.settings.XMLSymbolSettings; -import org.eclipse.lemminx.utils.XMLPositionUtility; -import org.eclipse.lsp4j.ClientCapabilities; -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeActionParams; -import org.eclipse.lsp4j.CodeLens; -import org.eclipse.lsp4j.CodeLensParams; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.CompletionList; -import org.eclipse.lsp4j.CompletionParams; -import org.eclipse.lsp4j.ConfigurationItem; -import org.eclipse.lsp4j.ConfigurationParams; -import org.eclipse.lsp4j.DefinitionParams; -import org.eclipse.lsp4j.DidChangeTextDocumentParams; -import org.eclipse.lsp4j.DidCloseTextDocumentParams; -import org.eclipse.lsp4j.DidOpenTextDocumentParams; -import org.eclipse.lsp4j.DidSaveTextDocumentParams; -import org.eclipse.lsp4j.DocumentFormattingParams; -import org.eclipse.lsp4j.DocumentHighlight; -import org.eclipse.lsp4j.DocumentHighlightParams; -import org.eclipse.lsp4j.DocumentLink; -import org.eclipse.lsp4j.DocumentLinkParams; -import org.eclipse.lsp4j.DocumentRangeFormattingParams; -import org.eclipse.lsp4j.DocumentSymbol; -import org.eclipse.lsp4j.DocumentSymbolParams; -import org.eclipse.lsp4j.FoldingRange; -import org.eclipse.lsp4j.FoldingRangeRequestParams; -import org.eclipse.lsp4j.Hover; -import org.eclipse.lsp4j.HoverParams; -import org.eclipse.lsp4j.LinkedEditingRangeParams; -import org.eclipse.lsp4j.LinkedEditingRanges; -import org.eclipse.lsp4j.Location; -import org.eclipse.lsp4j.LocationLink; -import org.eclipse.lsp4j.PublishDiagnosticsParams; -import org.eclipse.lsp4j.ReferenceParams; -import org.eclipse.lsp4j.RenameParams; -import org.eclipse.lsp4j.SelectionRange; -import org.eclipse.lsp4j.SelectionRangeParams; -import org.eclipse.lsp4j.SymbolInformation; -import org.eclipse.lsp4j.TextDocumentClientCapabilities; -import org.eclipse.lsp4j.TextDocumentContentChangeEvent; -import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.TextEdit; -import org.eclipse.lsp4j.TypeDefinitionParams; -import org.eclipse.lsp4j.WorkspaceEdit; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; -import org.eclipse.lsp4j.services.TextDocumentService; - -import com.google.gson.JsonPrimitive; - -/** - * XML text document service. - * - */ -public class XMLTextDocumentService implements TextDocumentService { - - private static final Logger LOGGER = Logger.getLogger(XMLTextDocumentService.class.getName()); - - private final XMLLanguageServer xmlLanguageServer; - private final TextDocuments> documents; - private SharedSettings sharedSettings; - private LimitExceededWarner limitExceededWarner; - - /** - * Enumeration for Validation triggered by. - * - */ - private static enum TriggeredBy { - didOpen, // - didChange, // - Other; - } - - /** - * Save context. - */ - class SaveContext extends AbstractSaveContext { - - private final Collection> documentsToValidate; - - public SaveContext(Object settings) { - super(settings); - this.documentsToValidate = new ArrayList<>(); - } - - public SaveContext(String uri) { - super(uri); - this.documentsToValidate = new ArrayList<>(); - } - - @Override - public void collectDocumentToValidate(Predicate validateDocumentPredicate) { - documents.all().stream().forEach(document -> { - DOMDocument xmlDocument = document.getModel().getNow(null); - if (xmlDocument != null && !documentsToValidate.contains(document) - && validateDocumentPredicate.test(xmlDocument)) { - documentsToValidate.add(document); - } - }); - } - - @Override - public DOMDocument getDocument(String uri) { - return xmlLanguageServer.getDocument(uri); - } - - public void triggerValidationIfNeeded() { - triggerValidationFor(documentsToValidate); - } - } - - final ScheduledExecutorService delayer = Executors.newScheduledThreadPool(2); - private boolean codeActionLiteralSupport; - private boolean hierarchicalDocumentSymbolSupport; - private boolean definitionLinkSupport; - private boolean typeDefinitionLinkSupport; - - public XMLTextDocumentService(XMLLanguageServer xmlLanguageServer) { - this.xmlLanguageServer = xmlLanguageServer; - DOMParser parser = DOMParser.getInstance(); - this.documents = new ModelTextDocuments((document, cancelChecker) -> { - return parser.parse(document, getXMLLanguageService().getResolverExtensionManager(), true, cancelChecker); - }); - this.sharedSettings = new SharedSettings(); - this.limitExceededWarner = null; - } - - public void updateClientCapabilities(ClientCapabilities capabilities, - ExtendedClientCapabilities extendedClientCapabilities) { - if (capabilities != null) { - TextDocumentClientCapabilities textDocumentClientCapabilities = capabilities.getTextDocument(); - if (textDocumentClientCapabilities != null) { - sharedSettings.getCompletionSettings().setCapabilities(textDocumentClientCapabilities.getCompletion()); - sharedSettings.getFoldingSettings().setCapabilities(textDocumentClientCapabilities.getFoldingRange()); - sharedSettings.getHoverSettings().setCapabilities(textDocumentClientCapabilities.getHover()); - sharedSettings.getValidationSettings() - .setCapabilities(textDocumentClientCapabilities.getPublishDiagnostics()); - codeActionLiteralSupport = textDocumentClientCapabilities.getCodeAction() != null - && textDocumentClientCapabilities.getCodeAction().getCodeActionLiteralSupport() != null; - hierarchicalDocumentSymbolSupport = textDocumentClientCapabilities.getDocumentSymbol() != null - && textDocumentClientCapabilities.getDocumentSymbol() - .getHierarchicalDocumentSymbolSupport() != null - && textDocumentClientCapabilities.getDocumentSymbol().getHierarchicalDocumentSymbolSupport(); - definitionLinkSupport = textDocumentClientCapabilities.getDefinition() != null - && textDocumentClientCapabilities.getDefinition().getLinkSupport() != null - && textDocumentClientCapabilities.getDefinition().getLinkSupport(); - typeDefinitionLinkSupport = textDocumentClientCapabilities.getTypeDefinition() != null - && textDocumentClientCapabilities.getTypeDefinition().getLinkSupport() != null - && textDocumentClientCapabilities.getTypeDefinition().getLinkSupport(); - } - // Workspace settings - sharedSettings.getWorkspaceSettings().setCapabilities(capabilities.getWorkspace()); - } - if (extendedClientCapabilities != null) { - // Extended client capabilities - sharedSettings.getCodeLensSettings().setCodeLens(extendedClientCapabilities.getCodeLens()); - sharedSettings - .setActionableNotificationSupport(extendedClientCapabilities.isActionableNotificationSupport()); - sharedSettings.setOpenSettingsCommandSupport(extendedClientCapabilities.isOpenSettingsCommandSupport()); - sharedSettings.setBindingWizardSupport(extendedClientCapabilities.isBindingWizardSupport()); - } - - } - - @Override - public CompletableFuture, CompletionList>> completion(CompletionParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - CompletionList list = getXMLLanguageService().doComplete(xmlDocument, params.getPosition(), sharedSettings, - cancelChecker); - return Either.forRight(list); - }); - } - - @Override - public CompletableFuture hover(HoverParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().doHover(xmlDocument, params.getPosition(), sharedSettings, cancelChecker); - }); - } - - /** - * Returns the indentation settings (`xml.format.tabSize` and - * `xml.format.insertSpaces`) for the document with the given URI. - * - * @param uri the uri of the document to get the indentation settings for - * @return the indentation settings (`xml.format.tabSize` and - * `xml.format.insertSpaces`) for the document with the given URI - */ - private CompletableFuture getIndentationSettings(@NonNull String uri) { - ConfigurationItem insertSpaces = new ConfigurationItem(); - insertSpaces.setScopeUri(uri); - insertSpaces.setSection("xml.format.insertSpaces"); - - ConfigurationItem tabSize = new ConfigurationItem(); - tabSize.setScopeUri(uri); - tabSize.setSection("xml.format.tabSize"); - - return xmlLanguageServer.getLanguageClient().configuration(new ConfigurationParams(Arrays.asList( // - insertSpaces, tabSize // - ))).thenApply(indentationSettings -> { - XMLFormattingOptions newOptions = new XMLFormattingOptions(); - if (indentationSettings.get(0) != null) { - newOptions.setInsertSpaces(((JsonPrimitive) indentationSettings.get(0)).getAsBoolean()); - } - if (indentationSettings.get(1) != null) { - newOptions.setTabSize(((JsonPrimitive) indentationSettings.get(1)).getAsInt()); - } - return newOptions; - }); - } - - @Override - public CompletableFuture> documentHighlight(DocumentHighlightParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().findDocumentHighlights(xmlDocument, params.getPosition(), cancelChecker); - }); - } - - @Override - public CompletableFuture>> documentSymbol( - DocumentSymbolParams params) { - - TextDocument document = getDocument(params.getTextDocument().getUri()); - if (document == null) { - return CompletableFuture.completedFuture(null); - } - XMLSymbolSettings symbolSettings = sharedSettings.getSymbolSettings(); - - if (!symbolSettings.isEnabled() || symbolSettings.isExcluded(document.getUri())) { - return CompletableFuture.completedFuture(Collections.emptyList()); - } - - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - boolean resultLimitExceeded = false; - List> symbols = null; - - if (hierarchicalDocumentSymbolSupport) { - DocumentSymbolsResult result = getXMLLanguageService().findDocumentSymbols(xmlDocument, symbolSettings, - cancelChecker); - resultLimitExceeded = result.isResultLimitExceeded(); - symbols = result // - .stream() // - .map(s -> { - Either e = Either.forRight(s); - return e; - }) // - .collect(Collectors.toList()); - } else { - SymbolInformationResult result = getXMLLanguageService().findSymbolInformations(xmlDocument, - symbolSettings, cancelChecker); - resultLimitExceeded = result.isResultLimitExceeded(); - symbols = result.stream() // - .map(s -> { - Either e = Either.forLeft(s); - return e; - }) // - .collect(Collectors.toList()); - } - if (resultLimitExceeded) { - // send warning - getLimitExceededWarner().onResultLimitExceeded(xmlDocument.getTextDocument().getUri(), - LimitFeature.SYMBOLS); - } - return symbols; - }); - } - - @Override - public CompletableFuture> formatting(DocumentFormattingParams params) { - return computeAsync((cancelChecker) -> { - String uri = params.getTextDocument().getUri(); - TextDocument document = getDocument(uri); - if (document == null) { - return null; - } - CompositeSettings settings = new CompositeSettings(getSharedSettings(), params.getOptions()); - return getXMLLanguageService().format(document, null, settings); - }); - } - - @Override - public CompletableFuture> rangeFormatting(DocumentRangeFormattingParams params) { - return computeAsync((cancelChecker) -> { - String uri = params.getTextDocument().getUri(); - TextDocument document = getDocument(uri); - if (document == null) { - return null; - } - CompositeSettings settings = new CompositeSettings(getSharedSettings(), params.getOptions()); - return getXMLLanguageService().format(document, params.getRange(), settings); - }); - } - - @Override - public CompletableFuture rename(RenameParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().doRename(xmlDocument, params.getPosition(), params.getNewName()); - }); - } - - @Override - public void didOpen(DidOpenTextDocumentParams params) { - TextDocument document = documents.onDidOpenTextDocument(params); - triggerValidationFor(document, TriggeredBy.didOpen); - } - - /** - * This method is triggered when the user types on an XML document. - */ - @Override - public void didChange(DidChangeTextDocumentParams params) { - TextDocument document = documents.onDidChangeTextDocument(params); - triggerValidationFor(document, TriggeredBy.didChange, params.getContentChanges()); - } - - @Override - public void didClose(DidCloseTextDocumentParams params) { - TextDocumentIdentifier identifier = params.getTextDocument(); - String uri = identifier.getUri(); - DOMDocument xmlDocument = getNowDOMDocument(uri); - // Remove the document from the cache - documents.onDidCloseTextDocument(params); - // Publish empty errors from the document - xmlLanguageServer.getLanguageClient() - .publishDiagnostics(new PublishDiagnosticsParams(uri, Collections.emptyList())); - getLimitExceededWarner().evictValue(uri); - // Manage didClose document lifecycle participants - if (xmlDocument != null) { - getXMLLanguageService().getDocumentLifecycleParticipants().forEach(participant -> { - try { - participant.didClose(xmlDocument); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while processing didClose for the participant '" - + participant.getClass().getName() + "'.", e); - } - }); - } - } - - private DOMDocument getNowDOMDocument(String uri) { - TextDocument document = documents.get(uri); - if (document != null) { - return ((ModelTextDocument) document).getModel().getNow(null); - } - return null; - } - - @Override - public CompletableFuture> foldingRange(FoldingRangeRequestParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().getFoldingRanges(xmlDocument, sharedSettings.getFoldingSettings(), - cancelChecker); - }); - } - - @Override - public CompletableFuture> documentLink(DocumentLinkParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().findDocumentLinks(xmlDocument); - }); - } - - @Override - public CompletableFuture, List>> definition( - DefinitionParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - if (definitionLinkSupport) { - return Either.forRight( - getXMLLanguageService().findDefinition(xmlDocument, params.getPosition(), cancelChecker)); - } - List locations = getXMLLanguageService() - .findDefinition(xmlDocument, params.getPosition(), cancelChecker) // - .stream() // - .map(locationLink -> XMLPositionUtility.toLocation(locationLink)) // - .collect(Collectors.toList()); - return Either.forLeft(locations); - }); - } - - @Override - public CompletableFuture, List>> typeDefinition( - TypeDefinitionParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - if (typeDefinitionLinkSupport) { - return Either.forRight( - getXMLLanguageService().findTypeDefinition(xmlDocument, params.getPosition(), cancelChecker)); - } - List locations = getXMLLanguageService() - .findTypeDefinition(xmlDocument, params.getPosition(), cancelChecker) // - .stream() // - .map(locationLink -> XMLPositionUtility.toLocation(locationLink)) // - .collect(Collectors.toList()); - return Either.forLeft(locations); - }); - } - - @Override - public CompletableFuture> references(ReferenceParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().findReferences(xmlDocument, params.getPosition(), params.getContext(), - cancelChecker); - }); - } - - @Override - public CompletableFuture> codeLens(CodeLensParams params) { - if (!sharedSettings.getCodeLensSettings().isEnabled()) { - return CompletableFuture.completedFuture(Collections.emptyList()); - } - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().getCodeLens(xmlDocument, sharedSettings.getCodeLensSettings(), - cancelChecker); - }); - } - - @Override - public CompletableFuture>> codeAction(CodeActionParams params) { - String uri = params.getTextDocument().getUri(); - return getIndentationSettings(uri) // - .handle((XMLFormattingOptions indentationSettings, Throwable err) -> { - if (indentationSettings != null) { - sharedSettings.getFormattingSettings().merge(indentationSettings); - } - return null; - }) // - .thenCombine(computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return xmlDocument; - }), (void_, xmlDocument) -> { - return (List>) getXMLLanguageService() - .doCodeActions(params.getContext(), params.getRange(), xmlDocument, sharedSettings) // - .stream() // - .map(ca -> { - if (codeActionLiteralSupport) { - Either e = Either.forRight(ca); - return e; - } else { - List arguments = Arrays.asList(uri, - xmlDocument.getTextDocument().getVersion(), - ca.getEdit().getDocumentChanges().get(0).getLeft().getEdits()); - Command command = new Command(ca.getTitle(), "_xml.applyCodeAction", arguments); - Either e = Either.forLeft(command); - return e; - } - }) // - .collect(Collectors.toList()); - }); - } - - @Override - public CompletableFuture> selectionRange(SelectionRangeParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().getSelectionRanges(xmlDocument, params.getPositions(), cancelChecker); - }); - } - - public CompletableFuture linkedEditingRange(LinkedEditingRangeParams params) { - return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> { - return getXMLLanguageService().findLinkedEditingRanges(xmlDocument, params.getPosition(), cancelChecker); - }); - } - - @Override - public void didSave(DidSaveTextDocumentParams params) { - computeAsync((monitor) -> { - // A document was saved, collect documents to revalidate - SaveContext context = new SaveContext(params.getTextDocument().getUri()); - doSave(context); - - // Manage didSave document lifecycle participants - final DOMDocument xmlDocument = getNowDOMDocument(params.getTextDocument().getUri()); - if (xmlDocument != null) { - getXMLLanguageService().getDocumentLifecycleParticipants().forEach(participant -> { - try { - participant.didSave(xmlDocument); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while processing didSave for the participant '" - + participant.getClass().getName() + "'.", e); - } - }); - } - return null; - }); - } - - /** - * Update settings of the language service. - * - * @param settings - */ - public void updateSettings(Object settings) { - SaveContext context = new SaveContext(settings); - doSave(context); - } - - void doSave(String uri) { - SaveContext context = new SaveContext(uri); - doSave(context); - } - - /** - * Save settings or XML file. - * - * @param context - */ - void doSave(SaveContext context) { - getXMLLanguageService().doSave(context); - context.triggerValidationIfNeeded(); - } - - private void triggerValidationFor(Collection> documents) { - if (!documents.isEmpty()) { - xmlLanguageServer.schedule(() -> { - documents.forEach(document -> { - try { - validate(document.getModel().getNow(null)); - } catch (CancellationException e) { - // Ignore the error and continue to validate other documents - } - }); - }, 500, TimeUnit.MILLISECONDS); - } - } - - private void triggerValidationFor(TextDocument document, TriggeredBy triggeredBy) { - triggerValidationFor(document, triggeredBy, null); - } - - @SuppressWarnings("unchecked") - private void triggerValidationFor(TextDocument document, TriggeredBy triggeredBy, - List changeEvents) { - ((ModelTextDocument) document).getModel()// - .thenAcceptAsync(xmlDocument -> { - // Validate the DOM document - validate(xmlDocument); - // Manage didOpen, didChange document lifecycle participants - switch (triggeredBy) { - case didOpen: - getXMLLanguageService().getDocumentLifecycleParticipants().forEach(participant -> { - try { - participant.didOpen(xmlDocument); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while processing didOpen for the participant '" - + participant.getClass().getName() + "'.", e); - } - }); - break; - case didChange: - getXMLLanguageService().getDocumentLifecycleParticipants().forEach(participant -> { - try { - participant.didChange(xmlDocument); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while processing didChange for the participant '" - + participant.getClass().getName() + "'.", e); - } - }); - break; - default: - // Do nothing - } - }); - } - - void validate(DOMDocument xmlDocument) throws CancellationException { - CancelChecker cancelChecker = xmlDocument.getCancelChecker(); - cancelChecker.checkCanceled(); - getXMLLanguageService().publishDiagnostics(xmlDocument, - params -> xmlLanguageServer.getLanguageClient().publishDiagnostics(params), - (doc) -> triggerValidationFor(doc, TriggeredBy.Other), sharedSettings.getValidationSettings(), - cancelChecker); - } - - private XMLLanguageService getXMLLanguageService() { - return xmlLanguageServer.getXMLLanguageService(); - } - - public void updateCompletionSettings(XMLCompletionSettings newCompletion) { - sharedSettings.getCompletionSettings().merge(newCompletion); - } - - public void updateSymbolSettings(XMLSymbolSettings newSettings) { - sharedSettings.getSymbolSettings().merge(newSettings); - } - - public void updateCodeLensSettings(XMLCodeLensSettings newSettings) { - sharedSettings.getCodeLensSettings().merge(newSettings); - } - - public void updatePreferences(XMLPreferences newPreferences) { - sharedSettings.getPreferences().merge(newPreferences); - } - - public XMLSymbolSettings getSharedSymbolSettings() { - return sharedSettings.getSymbolSettings(); - } - - public XMLCodeLensSettings getSharedCodeLensSettings() { - return sharedSettings.getCodeLensSettings(); - } - - public boolean isIncrementalSupport() { - return documents.isIncremental(); - } - - public XMLFormattingOptions getSharedFormattingSettings() { - return sharedSettings.getFormattingSettings(); - } - - public XMLValidationSettings getValidationSettings() { - return sharedSettings.getValidationSettings(); - } - - public XMLPreferences getPreferences() { - return sharedSettings.getPreferences(); - } - - public SharedSettings getSharedSettings() { - return this.sharedSettings; - } - - /** - * Returns the text document from the given uri. - * - * @param uri the uri - * @return the text document from the given uri. - */ - public ModelTextDocument getDocument(String uri) { - return documents.get(uri); - } - - public Collection> allDocuments() { - return documents.all(); - } - - public boolean documentIsOpen(String uri) { - ModelTextDocument document = getDocument(uri); - return document != null; - } - - /** - * Compute the DOM Document for a given uri in a future and then apply the given - * function. - * - * @param - * @param documentIdentifier the document indetifier. - * @param code a bi function that accepts a {@link CancelChecker} - * and parsed {@link DOMDocument} and returns the to - * be computed value - * @return the DOM Document for a given uri in a future and then apply the given - * function. - */ - public CompletableFuture computeDOMAsync(TextDocumentIdentifier documentIdentifier, - BiFunction code) { - ModelTextDocument document = getDocument(documentIdentifier.getUri()); - if (document != null) { - return computeModelAsync(document.getModel(), code); - } - return CompletableFuture.completedFuture(null); - } - - private static CompletableFuture computeModelAsync(CompletableFuture loadModel, - BiFunction code) { - CompletableFuture start = new CompletableFuture<>(); - CompletableFuture result = start.thenCombineAsync(loadModel, code); - CancelChecker cancelIndicator = () -> { - if (result.isCancelled()) - throw new CancellationException(); - }; - start.complete(cancelIndicator); - return result; - } - - public LimitExceededWarner getLimitExceededWarner() { - if (this.limitExceededWarner == null) { - this.limitExceededWarner = new LimitExceededWarner(this.xmlLanguageServer); - } - return this.limitExceededWarner; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/XMLWorkspaceService.java b/lemminx/src/main/java/org/eclipse/lemminx/XMLWorkspaceService.java deleted file mode 100644 index 38720a3f0..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/XMLWorkspaceService.java +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; - -import org.eclipse.lemminx.services.extensions.commands.IXMLCommandService; -import org.eclipse.lsp4j.DidChangeConfigurationParams; -import org.eclipse.lsp4j.DidChangeWatchedFilesParams; -import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.FileEvent; -import org.eclipse.lsp4j.SymbolInformation; -import org.eclipse.lsp4j.WorkspaceSymbolParams; -import org.eclipse.lsp4j.jsonrpc.CompletableFutures; -import org.eclipse.lsp4j.jsonrpc.ResponseErrorException; -import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; -import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; -import org.eclipse.lsp4j.services.WorkspaceService; - -/** - * XML workspace service. - * - */ -public class XMLWorkspaceService implements WorkspaceService, IXMLCommandService { - - private final XMLLanguageServer xmlLanguageServer; - - private final Map commands; - - public XMLWorkspaceService(XMLLanguageServer xmlLanguageServer) { - this.xmlLanguageServer = xmlLanguageServer; - this.commands = new HashMap<>(); - } - - @Override - public CompletableFuture> symbol(WorkspaceSymbolParams params) { - return null; - } - - @Override - public CompletableFuture executeCommand(ExecuteCommandParams params) { - synchronized (commands) { - IDelegateCommandHandler handler = commands.get(params.getCommand()); - if (handler == null) { - throw new ResponseErrorException(new ResponseError(ResponseErrorCode.InternalError, - "No command handler for the command: " + params.getCommand(), null)); - } - return CompletableFutures.computeAsync(cancelChecker -> { - try { - return handler.executeCommand(params, xmlLanguageServer.getSharedSettings(), cancelChecker); - } catch (Exception e) { - if (e instanceof ResponseErrorException) { - throw (ResponseErrorException) e; - } else if (e instanceof CancellationException) { - throw (CancellationException) e; - } - throw new ResponseErrorException( - new ResponseError(ResponseErrorCode.UnknownErrorCode, e.getMessage(), e)); - } - }); - } - } - - @Override - public void didChangeConfiguration(DidChangeConfigurationParams params) { - xmlLanguageServer.updateSettings(params.getSettings()); - xmlLanguageServer.getCapabilityManager().syncDynamicCapabilitiesWithPreferences(); - } - - @Override - public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) { - xmlLanguageServer.getXMLLanguageService().getWorkspaceServiceParticipants().forEach(participant -> participant.didChangeWorkspaceFolders(params)); - } - - @Override - public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - XMLTextDocumentService xmlTextDocumentService = (XMLTextDocumentService) xmlLanguageServer - .getTextDocumentService(); - List changes = params.getChanges(); - for (FileEvent change : changes) { - if (!xmlTextDocumentService.documentIsOpen(change.getUri())) { - xmlTextDocumentService.doSave(change.getUri()); - } - } - } - - @Override - public void registerCommand(String commandId, IDelegateCommandHandler handler) { - synchronized (commands) { - if (commands.containsKey(commandId)) { - throw new IllegalArgumentException("Command with id '" + commandId + "' is already registered"); - } - commands.put(commandId, handler); - } - } - - @Override - public void unregisterCommand(String commandId) { - synchronized (commands) { - commands.remove(commandId); - } - } - - @Override - public CompletableFuture executeClientCommand(ExecuteCommandParams command) { - return xmlLanguageServer.getLanguageClient().executeClientCommand(command); - } - - @Override - public void endCommandsRegistration() { - if (!commands.isEmpty()) { - xmlLanguageServer.getCapabilityManager().registerExecuteCommand(new ArrayList<>(commands.keySet())); - } - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/AbstractXMLNotifier.java b/lemminx/src/main/java/org/eclipse/lemminx/client/AbstractXMLNotifier.java deleted file mode 100644 index e46161945..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/AbstractXMLNotifier.java +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.eclipse.lemminx.services.IXMLNotificationService; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.MessageType; - -/** Sends a notification to the client via a jsonrpc notification - * while managing cache - */ -public abstract class AbstractXMLNotifier { - - private final IXMLNotificationService notificationService; - - protected final Map> cache; - - public AbstractXMLNotifier(IXMLNotificationService notificationService) { - this.notificationService = notificationService; - this.cache = new HashMap<>(); - } - - /** - * Returns true if value exists in the cache set - * identified by key and false otherwise - * - * @param key the key for the cache set - * @param value the value to check - * @return true if value exists in the cache set - * identified by key and false otherwise - */ - public boolean existsInCache(IXMLSettingFeature key, String value) { - return this.cache.get(key) != null && this.cache.get(key).contains(value); - } - - /** - * Returns true if values is equal to the cache set - * identified by key and false otherwise - * - * @param key the key for the cache set - * @param values the values set to check - * @return true if values is equal to the cache set - * identified by key and false otherwise - */ - public boolean existsInCache(IXMLSettingFeature key, Set values) { - return this.cache.get(key) != null && this.cache.get(key).equals(values); - } - - /** - * Adds value to the cache set identified by key - * - * If such cache set does not exist, this method will initialize it with - * value added - * - * @param key the key for the cache set to add to - * @param value the value to add - */ - public void addToCache(IXMLSettingFeature key, String value) { - if (this.cache.get(key) == null) { - this.cache.put(key, new HashSet()); - } - this.cache.get(key).add(value); - } - - /** - * Sets the cache set identified by key - * - * @param key the key for the cache set - * @param values the cache set - */ - public void setCacheValues(IXMLSettingFeature key, Set values) { - evictKey(key); - this.cache.put(key, new HashSet(values)); - } - - - /** - * Evicts the set identified by the provided key, from the cache - * - * @param key - */ - public void evictKey(IXMLSettingFeature key) { - Set setToEvict = this.cache.get(key); - if (setToEvict != null) { - setToEvict.clear(); - } - } - - /** - * Evicts the provided value from all cached sets - * - * @param value - */ - public void evictValue(String value) { - for (Set set: this.cache.values()) { - set.remove(value); - } - } - - protected void sendNotification(String message, MessageType messageType, Command... commands) { - notificationService.sendNotification(message, messageType, commands); - } - - protected SharedSettings getSharedSettings() { - return notificationService.getSharedSettings(); - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/ClientCommands.java b/lemminx/src/main/java/org/eclipse/lemminx/client/ClientCommands.java deleted file mode 100644 index 802f284b2..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/ClientCommands.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019-2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * Commonly used client commands - * - * @author Angelo ZERR - * - */ -public class ClientCommands { - - private ClientCommands() { - } - - /** - * Show references - */ - public static final String SHOW_REFERENCES = "xml.show.references"; - - /** - * Open settings command. This custom command is sent to the client in order to - * have the client open its settings UI. - */ - public static final String OPEN_SETTINGS = "xml.open.settings"; - - /** - * Open the binding wizard to bind the XML to a grammar/schema. - */ - public static final String OPEN_BINDING_WIZARD = "xml.open.binding.wizard"; - - /** - * Client command to open URI - */ - public static final String OPEN_URI = "xml.open.uri"; - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKind.java b/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKind.java deleted file mode 100644 index 38d149a57..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKind.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * CodeLens kind supported by the client. - * - * @author Angelo ZERR - * - * @see https://github.com/microsoft/language-server-protocol/issues/788 - */ -public class CodeLensKind { - - private CodeLensKind() { - } - - public static final String References = "references"; - - public static final String Implementations = "implementations"; - - public static final String Association = "association"; - - public static final String OpenUri = "open.uri"; -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKindCapabilities.java b/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKindCapabilities.java deleted file mode 100644 index defd1b2d5..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/CodeLensKindCapabilities.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -import java.util.List; - -import org.eclipse.xtext.xbase.lib.Pure; -import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; - -/** - * Specific capabilities for the `CodeLensKind`. - * - * @see https://github.com/microsoft/language-server-protocol/issues/788 - */ -@SuppressWarnings("all") -public class CodeLensKindCapabilities { - /** - * The codeLens kind values the client supports. When this property exists the - * client also guarantees that it will handle values outside its set gracefully - * and falls back to a default value when unknown. - * - * If this property is not present the client only supports the codeLens kinds - * from `File` to `Array` as defined in the initial version of the protocol. - */ - private List valueSet; - - public CodeLensKindCapabilities() { - } - - public CodeLensKindCapabilities(final List valueSet) { - this.valueSet = valueSet; - } - - /** - * The codeLens kind values the client supports. When this property exists the - * client also guarantees that it will handle values outside its set gracefully - * and falls back to a default value when unknown. - * - * If this property is not present the client only supports the codeLens kinds - * from `File` to `Array` as defined in the initial version of the protocol. - */ - @Pure - public List getValueSet() { - return this.valueSet; - } - - /** - * The codeLens kind values the client supports. When this property exists the - * client also guarantees that it will handle values outside its set gracefully - * and falls back to a default value when unknown. - * - * If this property is not present the client only supports the codeLens kinds - * from `File` to `Array` as defined in the initial version of the protocol. - */ - public void setValueSet(final List valueSet) { - this.valueSet = valueSet; - } - - @Override - @Pure - public String toString() { - ToStringBuilder b = new ToStringBuilder(this); - b.add("valueSet", this.valueSet); - return b.toString(); - } - - @Override - @Pure - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - CodeLensKindCapabilities other = (CodeLensKindCapabilities) obj; - if (this.valueSet == null) { - if (other.valueSet != null) { - return false; - } - } else if (!this.valueSet.equals(other.valueSet)) { - return false; - } - return true; - } - - @Override - @Pure - public int hashCode() { - return 31 * 1 + ((this.valueSet == null) ? 0 : this.valueSet.hashCode()); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedClientCapabilities.java b/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedClientCapabilities.java deleted file mode 100644 index 26bbd4aaf..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedClientCapabilities.java +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * Extended client capabilities not defined by the LSP. - * - * @author Angelo ZERR - * - * @see https://github.com/microsoft/language-server-protocol/issues/788 - */ -public class ExtendedClientCapabilities { - - private ExtendedCodeLensCapabilities codeLens; - - private boolean actionableNotificationSupport; - - private boolean openSettingsCommandSupport; - - private boolean bindingWizardSupport; - - private boolean shouldLanguageServerExitOnShutdown; - - public ExtendedCodeLensCapabilities getCodeLens() { - return codeLens; - } - - public void setCodeLens(ExtendedCodeLensCapabilities codeLens) { - this.codeLens = codeLens; - } - - /** - * Returns true if the client supports actionable notifications and false otherwise - * - * See {@link org.eclipse.lemminx.customservice.ActionableNotification} and - * {@link org.eclipse.lemminx.customservice.XMLLanguageClientAPI#actionableNotification} - * - * @return true if the client supports actionable notifications and false otherwise - */ - public boolean isActionableNotificationSupport() { - return actionableNotificationSupport; - } - - /** - * Sets the actionableNotificationSupport boolean - * - * @param actionableNotificationSupport - */ - public void setActionableNotificationSupport(boolean actionableNotificationSupport) { - this.actionableNotificationSupport = actionableNotificationSupport; - } - - /** - * Returns true if the client supports the open settings command and false otherwise - * - * See {@link org.eclipse.lemminx.client.ClientCommands#OPEN_SETTINGS} - * - * @return true if the client supports the open settings command and false otherwise - */ - public boolean isOpenSettingsCommandSupport() { - return openSettingsCommandSupport; - } - - /** - * Sets the openSettingsCommandSupport boolean - * - * @param openSettingsCommandSupport - */ - public void setOpenSettingsCommandSupport(boolean openSettingsCommandSupport) { - this.openSettingsCommandSupport = openSettingsCommandSupport; - } - - /** - * Returns true if the client supports the `xml.open.binding.wizard` command using dropdown and false otherwise - * - * @return bindingWizardSupport - */ - public boolean isBindingWizardSupport() { - return this.bindingWizardSupport; - } - - /** - * Sets the bindingWizardSupport boolean - * - * @param bindingWizardSupport - */ - public void setBindingWizardSupport(boolean bindingWizardSupport) { - this.bindingWizardSupport = bindingWizardSupport; - } - - /** - * Sets the boolean permitting language server to exit on client - * shutdown() request, without waiting for client to call exit() - * - * @param shouldLanguageServerExitOnShutdown - */ - public void setShouldLanguageServerExitOnShutdown(boolean shouldLanguageServerExitOnShutdown) { - this.shouldLanguageServerExitOnShutdown = shouldLanguageServerExitOnShutdown; - } - - /** - * Returns true if the client should exit on shutdown() request and - * avoid waiting for an exit() request - * - * @return true if the language server should exit on shutdown() request - */ - public boolean shouldLanguageServerExitOnShutdown() { - return shouldLanguageServerExitOnShutdown; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedCodeLensCapabilities.java b/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedCodeLensCapabilities.java deleted file mode 100644 index 4993ba915..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/ExtendedCodeLensCapabilities.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -import org.eclipse.lsp4j.DynamicRegistrationCapabilities; -import org.eclipse.xtext.xbase.lib.Pure; -import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; - -/** - * Extended capabilities specific to the `textDocument/codeLens` request. This capability doesn't belong to LSP specification. See proposal at - * https://github.com/microsoft/language-server-protocol/issues/788 - * - * @author Angelo ZERR - * - * @see https://github.com/microsoft/language-server-protocol/issues/788 - */ -@SuppressWarnings("all") -public class ExtendedCodeLensCapabilities extends DynamicRegistrationCapabilities { - /** - * Specific capabilities for the `CodeLensKind` in the `textDocument/codeLens` - * request. - */ - private CodeLensKindCapabilities codeLensKind; - - public ExtendedCodeLensCapabilities() { - } - - public ExtendedCodeLensCapabilities(final Boolean dynamicRegistration) { - super(dynamicRegistration); - } - - public ExtendedCodeLensCapabilities(final CodeLensKindCapabilities codeLensKind) { - this.codeLensKind = codeLensKind; - } - - public ExtendedCodeLensCapabilities(final CodeLensKindCapabilities codeLensKind, - final Boolean dynamicRegistration) { - super(dynamicRegistration); - this.codeLensKind = codeLensKind; - } - - /** - * Specific capabilities for the `CodeLensKind` in the `textDocument/codeLens` - * request. - */ - @Pure - public CodeLensKindCapabilities getCodeLensKind() { - return this.codeLensKind; - } - - /** - * Specific capabilities for the `CodeLensKind` in the `textDocument/codeLens` - * request. - */ - public void setCodeLensKind(final CodeLensKindCapabilities codeLensKind) { - this.codeLensKind = codeLensKind; - } - - @Override - @Pure - public String toString() { - ToStringBuilder b = new ToStringBuilder(this); - b.add("codeLensKind", this.codeLensKind); - b.add("dynamicRegistration", getDynamicRegistration()); - return b.toString(); - } - - @Override - @Pure - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - if (!super.equals(obj)) { - return false; - } - ExtendedCodeLensCapabilities other = (ExtendedCodeLensCapabilities) obj; - if (this.codeLensKind == null) { - if (other.codeLensKind != null) { - return false; - } - } else if (!this.codeLensKind.equals(other.codeLensKind)) { - return false; - } - return true; - } - - @Override - @Pure - public int hashCode() { - return 31 * super.hashCode() + ((this.codeLensKind == null) ? 0 : this.codeLensKind.hashCode()); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/IXMLSettingFeature.java b/lemminx/src/main/java/org/eclipse/lemminx/client/IXMLSettingFeature.java deleted file mode 100644 index c69cf2e2a..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/IXMLSettingFeature.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * Features that are associated with a particuliar settingId - */ -public interface IXMLSettingFeature { - /** - * Returns a displayable name for this feature - * - * @return a displayable name for this feature - */ - public String getName(); - - /** - * Returns the related settingId for this feature - * - * @return the related settingId for this feature - */ - public String getSettingId(); -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/InvalidPathWarner.java b/lemminx/src/main/java/org/eclipse/lemminx/client/InvalidPathWarner.java deleted file mode 100644 index f5e3a5e1b..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/InvalidPathWarner.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.lemminx.services.IXMLNotificationService; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.MessageType; - -/** - * This class sends a warning to the client via a jsonrpc notification - * - * The cache is a Map> - * - * where the keys are the feature names and the value is a set of file paths for - * which notifications have been sent already - */ -public class InvalidPathWarner extends AbstractXMLNotifier { - - public InvalidPathWarner(IXMLNotificationService notificationService ) { - super(notificationService); - } - - /** - * Sends the invalid path warning to the client only if the provided - * invalidPaths set does not match the feature's cache set - * - * After sending the warning, the feature's cache set is replaced - * with the provided invalidPaths set - * - * @param invalidPaths the set of invalid paths - * @param feature the feature - */ - public void onInvalidFilePath(Set invalidPaths, PathFeature feature) { - if (existsInCache(feature, invalidPaths)) { - return; - } - sendInvalidFilePathWarning(invalidPaths, feature); - setCacheValues(feature, new HashSet(invalidPaths)); - } - - private void sendInvalidFilePathWarning(Set invalidPaths, PathFeature feature) { - String message = createWarningMessage(feature.getSettingId(), invalidPaths); - - Command command = new Command("Configure setting", ClientCommands.OPEN_SETTINGS, - Collections.singletonList(feature.getSettingId())); - - super.sendNotification(message, MessageType.Error, command); - } - - private static String createWarningMessage(String settingId, Set invalidPaths) { - StringBuilder message = new StringBuilder("Invalid path"); - if (invalidPaths.size() > 1) { - message.append('s'); - } - message.append(" for setting '").append(settingId).append("': "); - - List list = new ArrayList<>(invalidPaths); - for (int i = 0; i < list.size(); i++) { - if (i != 0) { - message.append(", "); - } - message.append("'").append(list.get(i)).append("'"); - } - return message.toString(); - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/LimitExceededWarner.java b/lemminx/src/main/java/org/eclipse/lemminx/client/LimitExceededWarner.java deleted file mode 100644 index 339a0e66d..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/LimitExceededWarner.java +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -import java.net.URI; -import java.nio.file.Paths; -import java.util.Collections; - -import org.eclipse.lemminx.services.IXMLNotificationService; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.MessageType; - -/** - * LimitExceededWarner sends a warning to the client via a jsonrpc notification - * - * Cache is a Map> - * - * where the keys are the feature names and the values are the file paths for - * which notifications have been sent already - */ -public class LimitExceededWarner extends AbstractXMLNotifier { - - public LimitExceededWarner(IXMLNotificationService notificationService) { - super(notificationService); - } - - /** - * Sends the limit exceeded warning to the client only if the provided - * uri does not exist in the feature's cache set - * - * After sending the warning, the uri is added to the feature's cache set - * - * @param uri the file uri - * @param featureName the feature name - */ - public void onResultLimitExceeded(String uri, LimitFeature feature) { - int resultLimit = 0; - switch(feature) { - case SYMBOLS: - resultLimit = getSharedSettings().getSymbolSettings().getMaxItemsComputed(); - } - onResultLimitExceeded(uri, resultLimit, feature); - } - - /** - * Sends the limit exceeded warning to the client only if the provided - * uri does not exist in the cache - * - * After sending the warning, the uri is added to the cache - * - * @param uri the file uri - * @param resultLimit the result limit - * @param feature the feature - */ - public void onResultLimitExceeded(String uri, int resultLimit, LimitFeature feature) { - if (existsInCache(feature, uri)) { - return; - } - sendLimitExceededWarning(uri, resultLimit, feature); - addToCache(feature, uri); - } - - /** - * Send limit exceeded warning to client - * - * @param uri the file uri - * @param resultLimit the result limit - * @param feature the feature - */ - private void sendLimitExceededWarning(String uri, int resultLimit, LimitFeature feature) { - String filename = Paths.get(URI.create(uri)).getFileName().toString(); - String message = filename != null ? filename + ": " : ""; - message += "For performance reasons, " + feature.getName() + " have been limited to " + resultLimit - + " items.\nIf a new limit is set, please close and reopen this file to recompute " + feature.getName() + "."; - - // create command that opens the settings UI on the client side, in order to - // quickly edit the setting - Command command = new Command("Configure limit", ClientCommands.OPEN_SETTINGS, - Collections.singletonList(feature.getSettingId())); - - super.sendNotification(message, MessageType.Info ,command); - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/LimitFeature.java b/lemminx/src/main/java/org/eclipse/lemminx/client/LimitFeature.java deleted file mode 100644 index 0ba436b09..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/LimitFeature.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * Features that are associated with some limit - * - * For example, document symbols have a maximum limit for performance reasons - */ -public enum LimitFeature implements IXMLSettingFeature { - - SYMBOLS("document symbols", "xml.symbols.maxItemsComputed"); - - private final String name; - - private final String settingId; - - private LimitFeature(String name, String settingId) { - this.name = name; - this.settingId = settingId; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getSettingId() { - return settingId; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/client/PathFeature.java b/lemminx/src/main/java/org/eclipse/lemminx/client/PathFeature.java deleted file mode 100644 index e36b977d2..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/client/PathFeature.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.client; - -/** - * Features that are associated with filePaths - * - * For example, XML catalog support is associated with XML catalog filePaths - */ -public enum PathFeature implements IXMLSettingFeature { - - CATALOGS("XML catalog", "xml.catalogs"); - - private final String name; - private final String settingId; - - private PathFeature(String name, String settingId) { - this.name = name; - this.settingId = settingId; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getSettingId() { - return settingId; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/BadLocationException.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/BadLocationException.java deleted file mode 100644 index d241c6fb7..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/BadLocationException.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2005 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.lemminx.commons; - -/** - * Indicates the attempt to access a non-existing position. The attempt has been - * performed on a text store such as a document or string. - *

- * This class is not intended to be serialized. - *

- * - * This class is a copy/paste of org.eclipse.jface.text.BadLocationException. - */ -public class BadLocationException extends Exception { - - /** - * Serial version UID for this class. - *

- * Note: This class is not intended to be serialized. - *

- * - * @since 3.1 - */ - private static final long serialVersionUID = 3257281452776370224L; - - /** - * Creates a new bad location exception. - */ - public BadLocationException() { - super(); - } - - /** - * Creates a new bad location exception. - * - * @param message the exception message - */ - public BadLocationException(String message) { - super(message); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/CodeActionFactory.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/CodeActionFactory.java deleted file mode 100644 index 76e6edce6..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/CodeActionFactory.java +++ /dev/null @@ -1,191 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.commons; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeActionKind; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.CreateFile; -import org.eclipse.lsp4j.CreateFileOptions; -import org.eclipse.lsp4j.Diagnostic; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.ResourceOperation; -import org.eclipse.lsp4j.TextDocumentEdit; -import org.eclipse.lsp4j.TextDocumentItem; -import org.eclipse.lsp4j.TextEdit; -import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; -import org.eclipse.lsp4j.WorkspaceEdit; -import org.eclipse.lsp4j.jsonrpc.messages.Either; - -/** - * Factory for simple {@link CodeAction} - * - */ -public class CodeActionFactory { - - /** - * Create a CodeAction to remove the content from the given range. - * - * @param title - * @param range - * @param document - * @param diagnostic - * @return - */ - public static CodeAction remove(String title, Range range, TextDocumentItem document, Diagnostic diagnostic) { - return replace(title, range, "", document, diagnostic); - } - - /** - * Create a CodeAction to insert a new content at the end of the given range. - * - * @param title - * @param range - * @param insertText - * @param document - * @param diagnostic - * - * @return the CodeAction to insert a new content at the end of the given range. - */ - public static CodeAction insert(String title, Position position, String insertText, TextDocumentItem document, - Diagnostic diagnostic) { - CodeAction insertContentAction = new CodeAction(title); - insertContentAction.setKind(CodeActionKind.QuickFix); - insertContentAction.setDiagnostics(Arrays.asList(diagnostic)); - TextDocumentEdit textDocumentEdit = insertEdit(insertText, position, document); - WorkspaceEdit workspaceEdit = new WorkspaceEdit(Collections.singletonList(Either.forLeft(textDocumentEdit))); - - insertContentAction.setEdit(workspaceEdit); - return insertContentAction; - } - - /** - * Returns the text edit to insert a new content at the end of the given range. - * - * @param insertText text to insert. - * @param position the position. - * @param document the text document. - * - * @return the text edit to insert a new content at the end of the given range. - */ - public static TextDocumentEdit insertEdit(String insertText, Position position, TextDocumentItem document) { - TextEdit edit = insertEdit(insertText, position); - return insertEdits(document, Collections.singletonList(edit)); - } - - public static TextEdit insertEdit(String insertText, Position position) { - return new TextEdit(new Range(position, position), insertText); - } - - public static TextDocumentEdit insertEdits(TextDocumentItem document, List edits) { - VersionedTextDocumentIdentifier versionedTextDocumentIdentifier = new VersionedTextDocumentIdentifier( - document.getUri(), document.getVersion()); - return new TextDocumentEdit(versionedTextDocumentIdentifier, edits); - } - - public static CodeAction replace(String title, Range range, String replaceText, TextDocumentItem document, - Diagnostic diagnostic) { - TextEdit replace = new TextEdit(range, replaceText); - return replace(title, Collections.singletonList(replace), document, diagnostic); - } - - public static CodeAction replace(String title, List replace, TextDocumentItem document, - Diagnostic diagnostic) { - - CodeAction insertContentAction = new CodeAction(title); - insertContentAction.setKind(CodeActionKind.QuickFix); - insertContentAction.setDiagnostics(Arrays.asList(diagnostic)); - - VersionedTextDocumentIdentifier versionedTextDocumentIdentifier = new VersionedTextDocumentIdentifier( - document.getUri(), document.getVersion()); - TextDocumentEdit textDocumentEdit = new TextDocumentEdit(versionedTextDocumentIdentifier, replace); - WorkspaceEdit workspaceEdit = new WorkspaceEdit(Collections.singletonList(Either.forLeft(textDocumentEdit))); - insertContentAction.setEdit(workspaceEdit); - return insertContentAction; - } - - public static CodeAction replaceAt(String title, String replaceText, TextDocumentItem document, - Diagnostic diagnostic, Collection ranges) { - CodeAction insertContentAction = new CodeAction(title); - insertContentAction.setKind(CodeActionKind.QuickFix); - insertContentAction.setDiagnostics(Arrays.asList(diagnostic)); - - VersionedTextDocumentIdentifier versionedTextDocumentIdentifier = new VersionedTextDocumentIdentifier( - document.getUri(), document.getVersion()); - List edits = new ArrayList<>(); - for (Range range : ranges) { - TextEdit edit = new TextEdit(range, replaceText); - edits.add(edit); - } - TextDocumentEdit textDocumentEdit = new TextDocumentEdit(versionedTextDocumentIdentifier, edits); - WorkspaceEdit workspaceEdit = new WorkspaceEdit(Collections.singletonList(Either.forLeft(textDocumentEdit))); - - insertContentAction.setEdit(workspaceEdit); - return insertContentAction; - } - - /** - * Makes a CodeAction to create a file and add content to the file. - * - * @param title The displayed name of the CodeAction - * @param docURI The file to create - * @param content The text to put into the newly created document. - * @param diagnostic The diagnostic that this CodeAction will fix - */ - public static CodeAction createFile(String title, String docURI, String content, Diagnostic diagnostic) { - - List> actionsToTake = new ArrayList<>(2); - - // 1. create an empty file - actionsToTake.add(Either.forRight(new CreateFile(docURI, new CreateFileOptions(false, true)))); - - // 2. update the created file with the given content - VersionedTextDocumentIdentifier identifier = new VersionedTextDocumentIdentifier(docURI, 0); - TextEdit te = new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), content); - actionsToTake.add(Either.forLeft(new TextDocumentEdit(identifier, Collections.singletonList(te)))); - - WorkspaceEdit createAndAddContentEdit = new WorkspaceEdit(actionsToTake); - - CodeAction codeAction = new CodeAction(title); - codeAction.setEdit(createAndAddContentEdit); - codeAction.setDiagnostics(Collections.singletonList(diagnostic)); - codeAction.setKind(CodeActionKind.QuickFix); - - return codeAction; - } - - /** - * Makes a CodeAction to call a command from the available server commands. - * - * @param title The displayed name of the CodeAction - * @param commandId The id of the given command to add as CodeAction - * @param commandParams The document URI of the document the command is called on - * @param diagnostic The diagnostic that this CodeAction will fix - */ - public static CodeAction createCommand(String title, String commandId, List commandParams, Diagnostic diagnostic) { - CodeAction codeAction = new CodeAction(title); - Command command = new Command(title, commandId, commandParams); - codeAction.setCommand(command); - codeAction.setDiagnostics(Collections.singletonList(diagnostic)); - codeAction.setKind(CodeActionKind.QuickFix); - - return codeAction; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/ILineTracker.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/ILineTracker.java deleted file mode 100644 index 455334bee..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/ILineTracker.java +++ /dev/null @@ -1,150 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.lemminx.commons; -//package org.eclipse.jface.text; - -import org.eclipse.lsp4j.Position; - -/** - * A line tracker maps character positions to line numbers and vice versa. - * Initially the line tracker is informed about its underlying text in order to - * initialize the mapping information. After that, the line tracker is informed - * about all changes of the underlying text allowing for incremental updates of - * the mapping information. It is the client's responsibility to actively inform - * the line tacker about text changes. For example, when using a line tracker in - * combination with a document the document controls the line tracker. - *

- * In order to provide backward compatibility for clients of ILineTracker, extension - * interfaces are used to provide a means of evolution. The following extension interfaces - * exist: - *

    - *
  • {@link org.eclipse.jface.text.ILineTrackerExtension} since version 3.1 introducing the concept - * of rewrite sessions.
  • - *
- *

- * Clients may implement this interface or use the standard implementation - *

- * {@link org.eclipse.jface.text.DefaultLineTracker}or - * {@link org.eclipse.jface.text.ConfigurableLineTracker}. - */ -public interface ILineTracker { - - /** - * Returns the line delimiter of the specified line. Returns null if the - * line is not closed with a line delimiter. - * - * @param line the line whose line delimiter is queried - * @return the line's delimiter or null if line does not have a delimiter - * @exception BadLocationException if the line number is invalid in this tracker's line structure - */ - String getLineDelimiter(int line) throws BadLocationException; - - /** - * Computes the number of lines in the given text. - * - * @param text the text whose number of lines should be computed - * @return the number of lines in the given text - */ - int computeNumberOfLines(String text); - - /** - * Returns the number of lines. - *

- * Note that a document always has at least one line. - *

- * - * @return the number of lines in this tracker's line structure - */ - int getNumberOfLines(); - - /** - * Returns the number of lines which are occupied by a given text range. - * - * @param offset the offset of the specified text range - * @param length the length of the specified text range - * @return the number of lines occupied by the specified range - * @exception BadLocationException if specified range is unknown to this tracker - */ - int getNumberOfLines(int offset, int length) throws BadLocationException; - - /** - * Returns the position of the first character of the specified line. - * - * @param line the line of interest - * @return offset of the first character of the line - * @exception BadLocationException if the line is unknown to this tracker - */ - int getLineOffset(int line) throws BadLocationException; - - /** - * Returns length of the specified line including the line's delimiter. - * - * @param line the line of interest - * @return the length of the line - * @exception BadLocationException if line is unknown to this tracker - */ - int getLineLength(int line) throws BadLocationException; - - /** - * Returns the line number the character at the given offset belongs to. - * - * @param offset the offset whose line number to be determined - * @return the number of the line the offset is on - * @exception BadLocationException if the offset is invalid in this tracker - */ - int getLineNumberOfOffset(int offset) throws BadLocationException; - - /** - * Returns a line description of the line at the given offset. - * The description contains the start offset and the length of the line - * excluding the line's delimiter. - * - * @param offset the offset whose line should be described - * @return a region describing the line - * @exception BadLocationException if offset is invalid in this tracker - */ - Line getLineInformationOfOffset(int offset) throws BadLocationException; - - /** - * Returns a line description of the given line. The description - * contains the start offset and the length of the line excluding the line's - * delimiter. - * - * @param line the line that should be described - * @return a region describing the line - * @exception BadLocationException if line is unknown to this tracker - */ - Line getLineInformation(int line) throws BadLocationException; - - /** - * Informs the line tracker about the specified change in the tracked text. - * - * @param offset the offset of the replaced text - * @param length the length of the replaced text - * @param text the substitution text - * @exception BadLocationException if specified range is unknown to this tracker - */ - void replace(int offset, int length, String text) throws BadLocationException; - - /** - * Sets the tracked text to the specified text. - * - * @param text the new tracked text - */ - void set(String text); - - Position getPositionAt(int position) throws BadLocationException; - - int getOffsetAt(Position position) throws BadLocationException; -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/Line.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/Line.java deleted file mode 100644 index a4885b477..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/Line.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * This class is a copy/paste of org.eclipse.jface.text.Line - *******************************************************************************/ -package org.eclipse.lemminx.commons; - -/** - * Describes a line as a particular number of characters beginning at - * a particular offset, consisting of a particular number of characters, - * and being closed with a particular line delimiter. - */ -final class Line /*implements IRegion*/ { - - /** The offset of the line */ - public int offset; - /** The length of the line */ - public int length; - /** The delimiter of this line */ - public final String delimiter; - - /** - * Creates a new Line. - * - * @param offset the offset of the line - * @param end the last including character offset of the line - * @param delimiter the line's delimiter - */ - public Line(int offset, int end, String delimiter) { - this.offset= offset; - this.length= (end - offset) +1; - this.delimiter= delimiter; - } - - /** - * Creates a new Line. - * - * @param offset the offset of the line - * @param length the length of the line - */ - public Line(int offset, int length) { - this.offset= offset; - this.length= length; - this.delimiter= null; - } - - //@Override - public int getOffset() { - return offset; - } - - //@Override - public int getLength() { - return length; - } - - @Override - public String toString() { - return "Line [offset: " + offset + ", length: " + length + ", delimiter: '" + delimiter + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } -} - - diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/ListLineTracker.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/ListLineTracker.java deleted file mode 100644 index fe7639011..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/ListLineTracker.java +++ /dev/null @@ -1,452 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * This class is a copy/paste of org.eclipse.jface.text.ListLineTracker - *******************************************************************************/ -package org.eclipse.lemminx.commons; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.lsp4j.Position; - -/** - * Abstract, read-only implementation of ILineTracker. It lets the - * definition of line delimiters to subclasses. Assuming that '\n' is the only - * line delimiter, this abstract implementation defines the following line - * scheme: - *
    - *
  • "" -> [0,0] - *
  • "a" -> [0,1] - *
  • "\n" -> [0,1], [1,0] - *
  • "a\n" -> [0,2], [2,0] - *
  • "a\nb" -> [0,2], [2,1] - *
  • "a\nbc\n" -> [0,2], [2,3], [5,0] - *
- * This class must be subclassed. - * - * @since 3.2 - */ -class ListLineTracker implements ILineTracker { - - /** The predefined delimiters of this tracker */ - public final static String[] DELIMITERS = { "\r", "\n", "\r\n" }; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$ - /** A predefined delimiter information which is always reused as return value */ - private DelimiterInfo fDelimiterInfo = new DelimiterInfo(); - - /** The line information */ - private final List fLines = new ArrayList<>(); - /** The length of the tracked text */ - private int fTextLength; - - /** - * Combines the information of the occurrence of a line delimiter. - * delimiterIndex is the index where a line delimiter starts, - * whereas delimiterLength, indicates the length of the delimiter. - */ - protected static class DelimiterInfo { - public int delimiterIndex; - public int delimiterLength; - public String delimiter; - } - - /** - * Creates a new line tracker. - */ - protected ListLineTracker() { - } - - /** - * Binary search for the line at a given offset. - * - * @param offset the offset whose line should be found - * @return the line of the offset - */ - private int findLine(int offset) { - - if (fLines.size() == 0) { - return -1; - } - int left = 0; - int right = fLines.size(); - while (left < right - 1) { - int mid = (right + left) >> 1; - Line line = fLines.get(mid); - if (line.offset <= offset) { - left = mid; - } else { - right = mid; - } - } - return (fLines.get(left).offset > offset) ? left - 1 : left; - } - - @Override - public final Position getPositionAt(int offset) throws BadLocationException { - int lineNumber = getLineNumberOfOffset(offset); - int lines = fLines.size(); - int character = 0; - if (lines > 0) { - if (lineNumber == lines) { - Line l = fLines.get(lineNumber - 1); - character = offset - l.offset - l.length; - } else { - Line l = fLines.get(lineNumber); - character = offset - l.offset; - } - } - return new Position(lineNumber, character); - } - - /** - * Returns the number of lines covered by the specified text range. - * - * @param startLine the line where the text range starts - * @param offset the start offset of the text range - * @param length the length of the text range - * @return the number of lines covered by this text range - * @exception BadLocationException if range is undefined in this tracker - */ - private int getNumberOfLines(int startLine, int offset, int length) throws BadLocationException { - - if (length == 0) { - return 1; - } - - int target = offset + length; - - Line l = fLines.get(startLine); - - if (l.delimiter == null) { - return 1; - } - - if (l.offset + l.length > target) { - return 1; - } - - if (l.offset + l.length == target) { - return 2; - } - - return getLineNumberOfOffset(target) - startLine + 1; - } - - @Override - public final int getLineLength(int line) throws BadLocationException { - int lines = fLines.size(); - - if (line < 0 || line > lines) { - throw new BadLocationException(); - } - - if (lines == 0 || lines == line) { - return 0; - } - - Line l = fLines.get(line); - return l.length; - } - - @Override - public final int getLineNumberOfOffset(int position) throws BadLocationException { - if (position < 0) { - throw new BadLocationException("Negative offset : " + position); //$NON-NLS-1$ - } else if (position > fTextLength) { - throw new BadLocationException("Offset > length: " + position + " > " + fTextLength); //$NON-NLS-1$//$NON-NLS-2$ - } - - if (position == fTextLength) { - - int lastLine = fLines.size() - 1; - if (lastLine < 0) { - return 0; - } - - Line l = fLines.get(lastLine); - return (l.delimiter != null ? lastLine + 1 : lastLine); - } - - return findLine(position); - } - - @Override - public int getOffsetAt(Position position) throws BadLocationException { - int line = position.getLine(); - int lines = fLines.size(); - - if (line < 0 || line > lines) { - throw new BadLocationException("The line value, {" + line + "}, is out of bounds."); - } - - int lineOffset = -1; - int lineLength = -1; - if (lines == 0) { - lineOffset = 0; - lineLength = 0; - } else { - if (line == lines) { - Line l = fLines.get(line - 1); - lineOffset = l.offset + l.length; - lineLength = 0; - } else { - Line l = fLines.get(line); - lineOffset = l.offset; - lineLength = l.delimiter != null ? l.length - l.delimiter.length() : l.length; - } - } - int character = position.getCharacter(); - int offset = lineOffset + character; - int endLineOffset = lineOffset + lineLength; - if (offset > endLineOffset) { - throw new BadLocationException( - "The character value, {" + character + "} of the line" + line + "}, is out of bounds."); - } - return offset; - } - - @Override - public final Line getLineInformationOfOffset(int position) throws BadLocationException { - if (position > fTextLength) { - throw new BadLocationException("Offset > length: " + position + " > " + fTextLength); //$NON-NLS-1$//$NON-NLS-2$ - } - - if (position == fTextLength) { - int size = fLines.size(); - if (size == 0) { - return new Line(0, 0); - } - Line l = fLines.get(size - 1); - - return (l.delimiter != null ? new Line(fTextLength, 0) : new Line(fTextLength - l.length, l.length)); - } - - return getLineInformation(findLine(position)); - } - - @Override - public final Line getLineInformation(int line) throws BadLocationException { - int lines = fLines.size(); - - if (line < 0 || line > lines) { - throw new BadLocationException("The line value, {" + line + "}, is out of bounds."); - } - - if (lines == 0) { - return new Line(0, 0); - } - - if (line == lines) { - Line l = fLines.get(line - 1); - return new Line(l.offset + l.length, 0); - } - - Line l = fLines.get(line); - return (l.delimiter != null ? new Line(l.offset, l.length - l.delimiter.length()) : l); - } - - @Override - public final int getLineOffset(int line) throws BadLocationException { - int lines = fLines.size(); - - if (line < 0 || line > lines) { - throw new BadLocationException("The line value, {" + line + "}, is out of bounds."); - } - - if (lines == 0) { - return 0; - } - - if (line == lines) { - Line l = fLines.get(line - 1); - if (l.delimiter != null) { - return l.offset + l.length; - } - throw new BadLocationException(); - } - - Line l = fLines.get(line); - return l.offset; - } - - @Override - public final int getNumberOfLines() { - int lines = fLines.size(); - - if (lines == 0) { - return 1; - } - - Line l = fLines.get(lines - 1); - return (l.delimiter != null ? lines + 1 : lines); - } - - @Override - public final int getNumberOfLines(int position, int length) throws BadLocationException { - - if (position < 0 || position + length > fTextLength) { - throw new BadLocationException(); - } - - if (length == 0) { - return 1; - } - - return getNumberOfLines(getLineNumberOfOffset(position), position, length); - } - - @Override - public final int computeNumberOfLines(String text) { - int count = 0; - int start = 0; - DelimiterInfo delimiterInfo = nextDelimiterInfo(text, start); - while (delimiterInfo != null && delimiterInfo.delimiterIndex > -1) { - ++count; - start = delimiterInfo.delimiterIndex + delimiterInfo.delimiterLength; - delimiterInfo = nextDelimiterInfo(text, start); - } - return count; - } - - public final String getLineDelimiter(int line) throws BadLocationException { - int lines = fLines.size(); - - if (line < 0 || line > lines) { - throw new BadLocationException("The line value, {" + line + "}, is out of bounds."); - } - - if (lines == 0) { - return null; - } - - if (line == lines) { - return null; - } - - Line l = fLines.get(line); - return l.delimiter; - } - - /** - * Returns the information about the first delimiter found in the given text - * starting at the given offset. - * - * @param text the text to be searched - * @param offset the offset in the given text - * @return the information of the first found delimiter or null - */ - protected DelimiterInfo nextDelimiterInfo(String text, int offset) { - char ch; - int length = text.length(); - for (int i = offset; i < length; i++) { - - ch = text.charAt(i); - if (ch == '\r') { - - if (i + 1 < length) { - if (text.charAt(i + 1) == '\n') { - fDelimiterInfo.delimiter = DELIMITERS[2]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 2; - return fDelimiterInfo; - } - } - - fDelimiterInfo.delimiter = DELIMITERS[0]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 1; - return fDelimiterInfo; - - } else if (ch == '\n') { - - fDelimiterInfo.delimiter = DELIMITERS[1]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 1; - return fDelimiterInfo; - } - } - - return null; - - } - - /** - * Creates the line structure for the given text. Newly created lines are - * inserted into the line structure starting at the given position. Returns the - * number of newly created lines. - * - * @param text the text for which to create a line structure - * @param insertPosition the position at which the newly created lines are - * inserted into the tracker's line structure - * @param offset the offset of all newly created lines - * @return the number of newly created lines - */ - private int createLines(String text, int insertPosition, int offset) { - - int count = 0; - int start = 0; - DelimiterInfo delimiterInfo = nextDelimiterInfo(text, 0); - - while (delimiterInfo != null && delimiterInfo.delimiterIndex > -1) { - - int index = delimiterInfo.delimiterIndex + (delimiterInfo.delimiterLength - 1); - - if (insertPosition + count >= fLines.size()) { - fLines.add(new Line(offset + start, offset + index, delimiterInfo.delimiter)); - } else { - fLines.add(insertPosition + count, new Line(offset + start, offset + index, delimiterInfo.delimiter)); - } - - ++count; - start = index + 1; - delimiterInfo = nextDelimiterInfo(text, start); - } - - if (start < text.length()) { - if (insertPosition + count < fLines.size()) { - // there is a line below the current - Line l = fLines.get(insertPosition + count); - int delta = text.length() - start; - l.offset -= delta; - l.length += delta; - } else { - fLines.add(new Line(offset + start, offset + text.length() - 1, null)); - ++count; - } - } - - return count; - } - - @Override - public final void replace(int position, int length, String text) throws BadLocationException { - throw new UnsupportedOperationException(); - } - - @Override - public final void set(String text) { - fLines.clear(); - if (text != null) { - fTextLength = text.length(); - createLines(text, 0, 0); - } - } - - /** - * Returns the internal data structure, a {@link List} of {@link Line}s. Used - * only by {@link TreeLineTracker#TreeLineTracker(ListLineTracker)}. - * - * @return the internal list of lines. - */ - final List getLines() { - return fLines; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocument.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocument.java deleted file mode 100644 index f5eaa1157..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocument.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons; - -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -import java.util.logging.Logger; - -import org.eclipse.lsp4j.TextDocumentItem; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; -import org.eclipse.lsp4j.jsonrpc.CompletableFutures; - -/** - * A {@link TextDocument} which is associate to a model loaded in async. - * - * @author Angelo ZERR - * - * @param the model type (ex : DOM Document) - */ -public class ModelTextDocument extends TextDocument { - - private static final Logger LOGGER = Logger.getLogger(ModelTextDocument.class.getName()); - - private final BiFunction parse; - - private CompletableFuture model; - - public ModelTextDocument(TextDocumentItem document, BiFunction parse) { - super(document); - this.parse = parse; - } - - public ModelTextDocument(String text, String uri, BiFunction parse) { - super(text, uri); - this.parse = parse; - } - - /** - * Returns the completable future which loads the model. The process of parse od - * the model is stopped as soon as possible when text content changed. - * - * @return the completable future which loads the model. - */ - public CompletableFuture getModel() { - if (model == null) { - int version = super.getVersion(); - model = CompletableFutures.computeAsync((requestCancelChecker) -> { - long start = System.currentTimeMillis(); - try { - LOGGER.fine("Start parsing of model with version '" + version); - // Stop of parse process can be done when completable future is canceled or when - // version of document changes - MultiCancelChecker cancelChecker = new MultiCancelChecker(requestCancelChecker, - new TextDocumentVersionChecker(this, version)); - // parse the model - return parse.apply(this, cancelChecker); - } catch (CancellationException e) { - LOGGER.fine("Stop parsing parsing of model with version '" + version + "' in " - + (System.currentTimeMillis() - start) + "ms"); - throw e; - } finally { - LOGGER.fine("End parse of model with version '" + version + "' in " - + (System.currentTimeMillis() - start) + "ms"); - } - }); - } - return model; - } - - @Override - public void setText(String text) { - super.setText(text); - // text changed, cancel the completable future which load the model - cancelModel(); - } - - @Override - public void setVersion(int version) { - super.setVersion(version); - // version changed, cancel the completable future which load the model - cancelModel(); - } - - /** - * Cancel the completable future which loads the model. - */ - private void cancelModel() { - if (model != null) { - model.cancel(true); - model = null; - } - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocuments.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocuments.java deleted file mode 100644 index ccf33aa4d..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/ModelTextDocuments.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons; - -import java.util.function.BiFunction; - -import org.eclipse.lsp4j.TextDocumentItem; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * The cache of {@link TextDocument} linked to a model. - * - * @author Angelo ZERR - * - * @param the model type (ex : DOM Document) - */ -public class ModelTextDocuments extends TextDocuments> { - - private final BiFunction parse; - - public ModelTextDocuments(BiFunction parse) { - this.parse = parse; - } - - @Override - public ModelTextDocument createDocument(TextDocumentItem document) { - ModelTextDocument doc = new ModelTextDocument(document, parse); - doc.setIncremental(isIncremental()); - return doc; - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/MultiCancelChecker.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/MultiCancelChecker.java deleted file mode 100644 index 6e5d9486e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/MultiCancelChecker.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons; - -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * Multiple cancel checker. - * - * @author Angelo ZERR - * - */ -public class MultiCancelChecker implements CancelChecker { - - private CancelChecker[] checkers; - - public MultiCancelChecker(CancelChecker... checkers) { - this.checkers = checkers; - } - - @Override - public void checkCanceled() { - for (CancelChecker cancelChecker : checkers) { - cancelChecker.checkCanceled(); - } - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/ParentProcessWatcher.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/ParentProcessWatcher.java deleted file mode 100644 index d19dc13f7..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/ParentProcessWatcher.java +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 Red Hat Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.lemminx.commons; - -import static org.eclipse.lemminx.utils.platform.Platform.isWindows; - -import java.io.IOException; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.google.common.io.Closeables; - -import org.eclipse.lsp4j.jsonrpc.MessageConsumer; -import org.eclipse.lsp4j.services.LanguageServer; - -/** - * Watches the parent process PID and invokes exit if it is no longer available. - * This implementation waits for periods of inactivity to start querying the - * PIDs. - */ -public final class ParentProcessWatcher implements Runnable, Function { - - private static final Logger LOGGER = Logger.getLogger(ParentProcessWatcher.class.getName()); - private static final boolean isJava1x = System.getProperty("java.version").startsWith("1."); - - /** - * Exit code returned when XML Language Server is forced to exit. - */ - private static final int FORCED_EXIT_CODE = 1; - - private static final long INACTIVITY_DELAY_SECS = 30 * 1000; - private static final int POLL_DELAY_SECS = 10; - private volatile long lastActivityTime; - private final ProcessLanguageServer server; - private ScheduledFuture task; - private ScheduledExecutorService service; - - public interface ProcessLanguageServer extends LanguageServer { - - long getParentProcessId(); - - void exit(int exitCode); - } - - public ParentProcessWatcher(ProcessLanguageServer server) { - this.server = server; - service = Executors.newScheduledThreadPool(1); - task = service.scheduleWithFixedDelay(this, POLL_DELAY_SECS, POLL_DELAY_SECS, TimeUnit.SECONDS); - } - - @Override - public void run() { - if (!parentProcessStillRunning()) { - LOGGER.warning("Parent process stopped running, forcing server exit"); - task.cancel(true); - server.exit(FORCED_EXIT_CODE); - } - } - - /** - * Checks whether the parent process is still running. If not, then we assume it - * has crashed, and we have to terminate the Java Language Server. - * - * @return true if the parent process is still running - */ - private boolean parentProcessStillRunning() { - // Wait until parent process id is available - final long pid = server.getParentProcessId(); - if (pid == 0 || lastActivityTime > (System.currentTimeMillis() - INACTIVITY_DELAY_SECS)) { - return true; - } - String command; - if (isWindows) { - command = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\""; - } else { - command = "kill -0 " + pid; - } - Process process = null; - boolean finished = false; - try { - process = Runtime.getRuntime().exec(command); - finished = process.waitFor(POLL_DELAY_SECS, TimeUnit.SECONDS); - if (!finished) { - process.destroy(); - finished = process.waitFor(POLL_DELAY_SECS, TimeUnit.SECONDS); // wait for the process to stop - } - if (isWindows && finished && process.exitValue() > 1) { - // the tasklist command should return 0 (parent process exists) or 1 (parent process doesn't exist) - LOGGER.warning("The tasklist command: '" + command + "' returns " + process.exitValue()); - return true; - } - return !finished || process.exitValue() == 0; - } catch (IOException | InterruptedException e) { - LOGGER.log(Level.WARNING, e.getMessage(), e); - return true; - } finally { - if (process != null) { - if (!finished) { - process.destroyForcibly(); - } - // Terminating or destroying the Process doesn't close the process handle on Windows. - // It is only closed when the Process object is garbage collected (in its finalize() method). - // On Windows, when the Java LS is idle, we need to explicitly request a GC, - // to prevent an accumulation of zombie processes, as finalize() will be called. - if (isWindows) { - // Java >= 9 doesn't close the handle when the process is garbage collected - // We need to close the opened streams - if (!isJava1x) { - Closeables.closeQuietly(process.getInputStream()); - Closeables.closeQuietly(process.getErrorStream()); - try { - Closeables.close(process.getOutputStream(), false); - } catch (IOException e) { - } - } - System.gc(); - } - } - } - - } - - @Override - public MessageConsumer apply(final MessageConsumer consumer) { - //inject our own consumer to refresh the timestamp - return message -> { - lastActivityTime=System.currentTimeMillis(); - consumer.consume(message); - }; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/SnippetsBuilder.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/SnippetsBuilder.java deleted file mode 100644 index 1fdfe4c06..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/SnippetsBuilder.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.commons; - -import java.util.Collection; - -/** - * Snippet syntax utilities. - * - * @see https://github.com/Microsoft/language-server-protocol/blob/master/snippetSyntax.md - */ -public class SnippetsBuilder { - - private SnippetsBuilder() { - - } - - public static void tabstops(int index, StringBuilder snippets) { - snippets.append("$"); - snippets.append(index); - } - - public static String tabstops(int index) { - StringBuilder snippets = new StringBuilder(); - snippets.append("$"); - snippets.append(index); - return snippets.toString(); - } - - public static void placeholders(int index, String text, StringBuilder snippets) { - snippets.append("${"); - snippets.append(index); - snippets.append(":"); - snippets.append(text); - snippets.append("}"); - } - - /** - * Returns the LSP choices snippets content. - * - * @param index the snippet index. - * @param values the values for the choice. - * @return the LSP choices snippets content. - * - * @see https://github.com/Microsoft/language-server-protocol/blob/master/snippetSyntax.md#choice - */ - public static String choice(int index, Collection values) { - StringBuilder snippets = new StringBuilder(); - choice(index, values, snippets); - return snippets.toString(); - } - - /** - * Add LSP choices snippets in the given snippets content. - * - * @param index the snippet index. - * @param values the values for the choice. - * @return - * - * @see https://github.com/Microsoft/language-server-protocol/blob/master/snippetSyntax.md#choice - */ - public static void choice(int index, Collection values, StringBuilder snippets) { - snippets.append("${"); - snippets.append(index); - snippets.append("|"); - int i = 0; - for (String value : values) { - if (i > 0) { - snippets.append(","); - } - snippets.append(value); - i++; - } - snippets.append("|"); - snippets.append("}"); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocument.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocument.java deleted file mode 100644 index b80247bb4..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocument.java +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.commons; - -import java.util.List; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.TextDocumentContentChangeEvent; -import org.eclipse.lsp4j.TextDocumentItem; - -/** - * Text document extends LSP4j {@link TextDocumentItem} to provide methods to - * retrieve position. - * - */ -public class TextDocument extends TextDocumentItem { - - private static final Logger LOGGER = Logger.getLogger(TextDocument.class.getName()); - - private final Object lock = new Object(); - - private static String DEFAULT_DELIMTER = System.lineSeparator(); - - private ILineTracker lineTracker; - - private boolean incremental; - - public TextDocument(TextDocumentItem document) { - this(document.getText(), document.getUri()); - super.setVersion(document.getVersion()); - super.setLanguageId(document.getLanguageId()); - } - - public TextDocument(String text, String uri) { - super.setUri(uri); - super.setText(text); - } - - public void setIncremental(boolean incremental) { - this.incremental = incremental; - // reset line tracker - lineTracker = null; - getLineTracker(); - } - - public boolean isIncremental() { - return incremental; - } - - public Position positionAt(int position) throws BadLocationException { - ILineTracker lineTracker = getLineTracker(); - return lineTracker.getPositionAt(position); - } - - public int offsetAt(Position position) throws BadLocationException { - ILineTracker lineTracker = getLineTracker(); - return lineTracker.getOffsetAt(position); - } - - public String lineText(int lineNumber) throws BadLocationException { - ILineTracker lineTracker = getLineTracker(); - Line line = lineTracker.getLineInformation(lineNumber); - String text = super.getText(); - return text.substring(line.offset, line.offset + line.length); - } - - public String lineDelimiter(int lineNumber) throws BadLocationException { - ILineTracker lineTracker = getLineTracker(); - String lineDelimiter = lineTracker.getLineDelimiter(lineNumber); - if (lineDelimiter == null) { - if (lineTracker.getNumberOfLines() > 0) { - lineDelimiter = lineTracker.getLineInformation(0).delimiter; - } - } - if (lineDelimiter == null) { - lineDelimiter = DEFAULT_DELIMTER; - } - return lineDelimiter; - } - - public Range getWordRangeAt(int textOffset, Pattern wordDefinition) { - try { - Position pos = positionAt(textOffset); - ILineTracker lineTracker = getLineTracker(); - Line line = lineTracker.getLineInformation(pos.getLine()); - String text = super.getText(); - String lineText = text.substring(line.offset, textOffset); - int position = lineText.length(); - Matcher m = wordDefinition.matcher(lineText); - int currentPosition = 0; - while (currentPosition != position) { - if (m.find()) { - currentPosition = m.end(); - if (currentPosition == position) { - return new Range(new Position(pos.getLine(), m.start()), pos); - } - } else { - currentPosition++; - } - m.region(currentPosition, position); - } - return new Range(pos, pos); - } catch (BadLocationException e) { - return null; - } - } - - private ILineTracker getLineTracker() { - if (lineTracker == null) { - lineTracker = createLineTracker(); - } - return lineTracker; - } - - private synchronized ILineTracker createLineTracker() { - if (lineTracker != null) { - return lineTracker; - } - ILineTracker lineTracker = isIncremental() ? new TreeLineTracker(new ListLineTracker()) : new ListLineTracker(); - lineTracker.set(super.getText()); - return lineTracker; - } - - /** - * Update text of the document by using the changes and according the - * incremental support. - * - * @param changes the text document changes. - */ - public void update(List changes) { - if (changes.size() < 1) { - // no changes, ignore it. - return; - } - if (isIncremental()) { - try { - long start = System.currentTimeMillis(); - synchronized (lock) { - // Initialize buffer and line tracker from the current text document - StringBuilder buffer = new StringBuilder(getText()); - - // Loop for each changes and update the buffer - for (int i = 0; i < changes.size(); i++) { - - TextDocumentContentChangeEvent changeEvent = changes.get(i); - Range range = changeEvent.getRange(); - int length = 0; - - if (range != null) { - length = changeEvent.getRangeLength().intValue(); - } else { - // range is optional and if not given, the whole file content is replaced - length = buffer.length(); - range = new Range(positionAt(0), positionAt(length)); - } - String text = changeEvent.getText(); - int startOffset = offsetAt(range.getStart()); - buffer.replace(startOffset, startOffset + length, text); - lineTracker.replace(startOffset, length, text); - } - // Update the new text content from the updated buffer - setText(buffer.toString()); - } - LOGGER.fine("Text document content updated in " + (System.currentTimeMillis() - start) + "ms"); - } catch (BadLocationException e) { - // Should never occur. - } - } else { - // like vscode does, get the last changes - // see - // https://github.com/Microsoft/vscode-languageserver-node/blob/master/server/src/main.ts - TextDocumentContentChangeEvent last = changes.size() > 0 ? changes.get(changes.size() - 1) : null; - if (last != null) { - setText(last.getText()); - lineTracker.set(last.getText()); - } - } - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocumentVersionChecker.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocumentVersionChecker.java deleted file mode 100644 index 6fbf969b8..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocumentVersionChecker.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons; - -import java.util.concurrent.CancellationException; - -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * A {@link CancelChecker} implementation to throw a - * {@link CancellationException} when version of {@link TextDocument} changed. - * - * @author Angelo ZERR - * - */ -public class TextDocumentVersionChecker implements CancelChecker { - - private final TextDocument textDocument; - - private final int version; - - public TextDocumentVersionChecker(TextDocument textDocument, int version) { - this.textDocument = textDocument; - this.version = version; - } - - @Override - public void checkCanceled() { - if (textDocument.getVersion() != version) { - // the text document version has changed - throw new CancellationException("Text document version '" + version + "' has changed to version '" - + textDocument.getVersion() + "."); - } - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocuments.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocuments.java deleted file mode 100644 index fdb6a3cd0..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/TextDocuments.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.commons; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.lsp4j.DidChangeTextDocumentParams; -import org.eclipse.lsp4j.DidCloseTextDocumentParams; -import org.eclipse.lsp4j.DidOpenTextDocumentParams; -import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.eclipse.lsp4j.TextDocumentItem; - -/** - * A manager for simple text documents - */ -public class TextDocuments { - - private final Map documents; - - private boolean incremental = true; //default on - - public TextDocuments() { - documents = new HashMap<>(); - } - - /** - * Set the incremental support. - * - * @param incremental - */ - public void setIncremental(boolean incremental) { - this.incremental = incremental; - synchronized (documents) { - documents.values().forEach(document -> document.setIncremental(incremental)); - } - } - - /** - * Returns true if text document is managed in incremental mode and false - * otherwise. - * - * @return true if text document is managed in incremental mode and false - * otherwise. - */ - public boolean isIncremental() { - return incremental; - } - - /** - * Returns the document for the given URI. Returns undefined if the document is - * not mananged by this instance. - * - * @param uri The text document's URI to retrieve. - * @return the text document or `undefined`. - */ - public T get(String uri) { - synchronized (documents) { - return documents.get(uri); - } - } - - public T createDocument(TextDocumentItem document) { - TextDocument doc = new TextDocument(document); - doc.setIncremental(isIncremental()); - return (T) doc; - } - - public T onDidChangeTextDocument(DidChangeTextDocumentParams params) { - synchronized (documents) { - T document = getDocument(params.getTextDocument()); - if (document != null) { - document.setVersion(params.getTextDocument().getVersion()); - document.update(params.getContentChanges()); - return document; - } - } - return null; - } - - public T onDidOpenTextDocument(DidOpenTextDocumentParams params) { - TextDocumentItem item = params.getTextDocument(); - synchronized (documents) { - T document = createDocument(item); - documents.put(document.getUri(), document); - return document; - } - } - - public T onDidCloseTextDocument(DidCloseTextDocumentParams params) { - synchronized (documents) { - T document = getDocument(params.getTextDocument()); - if (document != null) { - documents.remove(params.getTextDocument().getUri()); - } - return document; - } - } - - private T getDocument(TextDocumentIdentifier identifier) { - return documents.get(identifier.getUri()); - } - - /** - * Returns the all opened documents. - * - * @return the all opened documents. - */ - public Collection all() { - synchronized (documents) { - return documents.values(); - } - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/TreeLineTracker.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/TreeLineTracker.java deleted file mode 100644 index dca2c0a35..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/TreeLineTracker.java +++ /dev/null @@ -1,1490 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2015 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.lemminx.commons; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - -import org.eclipse.lemminx.commons.ListLineTracker.DelimiterInfo; -import org.eclipse.lsp4j.Position; - -/** - * Abstract implementation of ILineTracker. It lets the definition - * of line delimiters to subclasses. Assuming that '\n' is the only line - * delimiter, this abstract implementation defines the following line scheme: - *
    - *
  • "" -> [0,0] - *
  • "a" -> [0,1] - *
  • "\n" -> [0,1], [1,0] - *
  • "a\n" -> [0,2], [2,0] - *
  • "a\nb" -> [0,2], [2,1] - *
  • "a\nbc\n" -> [0,2], [2,3], [5,0] - *
- *

- * This class must be subclassed. - *

- *

- * Performance: The query operations perform in O(log n) - * where n is the number of lines in the document. The modification - * operations roughly perform in O(l * log n) where n is the - * number of lines in the document and l is the sum of the number of - * removed, added or modified lines. - *

- * - * @since 3.2 - */ -public class TreeLineTracker implements ILineTracker { - - /** The predefined delimiters of this tracker */ - public final static String[] DELIMITERS = { "\r", "\n", "\r\n" }; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$ - /** A predefined delimiter information which is always reused as return value */ - private DelimiterInfo fDelimiterInfo = new DelimiterInfo(); - - /* - * Differential Balanced Binary Tree - * - * Assumption: lines cannot overlap => there exists a total ordering of the - * lines by their offset, which is the same as the ordering by line number - * - * Base idea: store lines in a binary search tree - the key is the line number / - * line offset -> lookup_line is O(log n) -> lookup_offset is O(log n) - a - * change in a line somewhere will change any succeeding line numbers / line - * offsets -> replace is O(n) - * - * Differential tree: instead of storing the key (line number, line offset) - * directly, every node stores the difference between its key and its parent's - * key - the sort key is still the line number / line offset, but it remains - * "virtual" - inserting a node (a line) really increases the virtual key of all - * succeeding nodes (lines), but this fact will not be realized in the key - * information encoded in the nodes. -> any change only affects the nodes in the - * node's parent chain, although more bookkeeping has to be done when changing a - * node or balancing the tree -> replace is O(log n) -> line offsets and line - * numbers have to be computed when walking the tree from the root / from a node - * -> still O(log n) - * - * The balancing algorithm chosen does not depend on the differential tree - * property. An AVL tree implementation has been chosen for simplicity. - */ - - /* - * Turns assertions on/off. Don't make this a a debug option for performance - * reasons - this way the compiler can optimize the asserts away. - */ - private static final boolean ASSERT = false; - - /** - * The empty delimiter of the last line. The last line and only the last line - * must have this zero-length delimiter. - */ - private static final String NO_DELIM = ""; //$NON-NLS-1$ - - /** - * A node represents one line. Its character and line offsets are 0-based and - * relative to the subtree covered by the node. All nodes under the left subtree - * represent lines before, all nodes under the right subtree lines after the - * current node. - */ - private static final class Node { - Node(int length, String delimiter) { - this.length = length; - this.delimiter = delimiter; - } - - /** - * The line index in this node's line tree, or equivalently, the number of lines - * in the left subtree. - */ - int line; - /** - * The line offset in this node's line tree, or equivalently, the number of - * characters in the left subtree. - */ - int offset; - /** The number of characters in this line. */ - int length; - /** The line delimiter of this line, needed to answer the delimiter query. */ - String delimiter; - /** The parent node, null if this is the root node. */ - Node parent; - /** The left subtree, possibly null. */ - Node left; - /** The right subtree, possibly null. */ - Node right; - /** The balance factor. */ - byte balance; - - @Override - public final String toString() { - String bal; - switch (balance) { - case 0: - bal = "="; //$NON-NLS-1$ - break; - case 1: - bal = "+"; //$NON-NLS-1$ - break; - case 2: - bal = "++"; //$NON-NLS-1$ - break; - case -1: - bal = "-"; //$NON-NLS-1$ - break; - case -2: - bal = "--"; //$NON-NLS-1$ - break; - default: - bal = Byte.toString(balance); - } - return "[" + offset + "+" + pureLength() + "+" + delimiter.length() + "|" + line + "|" + bal + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ - } - - /** - * Returns the pure (without the line delimiter) length of this line. - * - * @return the pure line length - */ - int pureLength() { - return length - delimiter.length(); - } - } - - /** - * The root node of the tree, never null. - */ - private Node fRoot = new Node(0, NO_DELIM); - - /** - * Creates a new line tracker. - */ - protected TreeLineTracker() { - } - - /** - * Package visible constructor for creating a tree tracker from a list tracker. - * - * @param tracker the list line tracker - */ - public TreeLineTracker(ListLineTracker tracker) { - final List lines = tracker.getLines(); - final int n = lines.size(); - if (n == 0) { - return; - } - - Line line = lines.get(0); - String delim = line.delimiter; - if (delim == null) { - delim = NO_DELIM; - } - int length = line.length; - fRoot = new Node(length, delim); - Node node = fRoot; - - for (int i = 1; i < n; i++) { - line = lines.get(i); - delim = line.delimiter; - if (delim == null) { - delim = NO_DELIM; - } - length = line.length; - node = insertAfter(node, length, delim); - } - - if (node.delimiter != NO_DELIM) { - insertAfter(node, 0, NO_DELIM); - } - - if (ASSERT) { - checkTree(); - } - } - - /** - * Returns the node (line) including a certain offset. If the offset is between - * two lines, the line starting at offset is returned. - *

- * This means that for offsets smaller than the length, the following holds: - *

- *

- * line.offset <= offset < line.offset + offset.length. - *

- *

- * If offset is the document length, then this is true: - *

- *

- * offset= line.offset + line.length. - *

- * - * @param offset a document offset - * @return the line starting at or containing offset - * @throws BadLocationException if the offset is invalid - */ - private Node nodeByOffset(final int offset) throws BadLocationException { - /* - * Works for any binary search tree. - */ - int remaining = offset; - Node node = fRoot; - while (true) { - if (node == null) { - fail(offset); - } - - if (remaining < node.offset) { - node = node.left; - } else { - remaining -= node.offset; - if (remaining < node.length || remaining == node.length && node.right == null) { // last line - break; - } - remaining -= node.length; - node = node.right; - } - } - - return node; - } - - /** - * Returns the line number for the given offset. If the offset is between two - * lines, the line starting at offset is returned. The last line is - * returned if offset is equal to the document length. - * - * @param offset a document offset - * @return the line number starting at or containing offset - * @throws BadLocationException if the offset is invalid - */ - private int lineByOffset(final int offset) throws BadLocationException { - /* - * Works for any binary search tree. - */ - int remaining = offset; - Node node = fRoot; - int line = 0; - - while (true) { - if (node == null) { - fail(offset); - } - - if (remaining < node.offset) { - node = node.left; - } else { - remaining -= node.offset; - line += node.line; - if (remaining < node.length || remaining == node.length && node.right == null) { - return line; - } - - remaining -= node.length; - line++; - node = node.right; - } - } - } - - /** - * Returns the node (line) with the given line number. Note that the last line - * is always incomplete, i.e. has the {@link #NO_DELIM} delimiter. - * - * @param line a line number - * @return the line with the given line number - * @throws BadLocationException if the line is invalid - */ - private Node nodeByLine(final int line) throws BadLocationException { - /* - * Works for any binary search tree. - */ - int remaining = line; - Node node = fRoot; - - while (true) { - if (node == null) { - fail(line); - } - - if (remaining == node.line) { - break; - } - if (remaining < node.line) { - node = node.left; - } else { - remaining -= node.line + 1; - node = node.right; - } - } - - return node; - } - - /** - * Returns the offset for the given line number. Note that the last line is - * always incomplete, i.e. has the {@link #NO_DELIM} delimiter. - * - * @param line a line number - * @return the line offset with the given line number - * @throws BadLocationException if the line is invalid - */ - private int offsetByLine(final int line) throws BadLocationException { - /* - * Works for any binary search tree. - */ - int remaining = line; - int offset = 0; - Node node = fRoot; - - while (true) { - if (node == null) { - fail(line); - } - - if (remaining == node.line) { - return offset + node.offset; - } - - if (remaining < node.line) { - node = node.left; - } else { - remaining -= node.line + 1; - offset += node.offset + node.length; - node = node.right; - } - } - } - - /** - * Left rotation - the given node is rotated down, its right child is rotated - * up, taking the previous structural position of node. - * - * @param node the node to rotate around - */ - private void rotateLeft(Node node) { - // if (ASSERT) Assert.isNotNull(node); - Node child = node.right; - // if (ASSERT) Assert.isNotNull(child); - boolean leftChild = node.parent == null || node == node.parent.left; - - // restructure - setChild(node.parent, child, leftChild); - - setChild(node, child.left, false); - setChild(child, node, true); - - // update relative info - // child becomes the new parent, its line and offset counts increase as the - // former parent - // moves under child's left subtree - child.line += node.line + 1; - child.offset += node.offset + node.length; - } - - /** - * Right rotation - the given node is rotated down, its left child is rotated - * up, taking the previous structural position of node. - * - * @param node the node to rotate around - */ - private void rotateRight(Node node) { - // if (ASSERT) Assert.isNotNull(node); - Node child = node.left; - // if (ASSERT) Assert.isNotNull(child); - boolean leftChild = node.parent == null || node == node.parent.left; - - setChild(node.parent, child, leftChild); - - setChild(node, child.right, true); - setChild(child, node, false); - - // update relative info - // node loses its left subtree, except for what it keeps in its new subtree - // this is exactly the amount in child - node.line -= child.line + 1; - node.offset -= child.offset + child.length; - } - - /** - * Helper method for moving a child, ensuring that parent pointers are set - * correctly. - * - * @param parent the new parent of child, null to - * replace the root node - * @param child the new child of parent, may be - * null - * @param isLeftChild true if child shall become - * parent's left child, false if it - * shall become parent's right child - */ - private void setChild(Node parent, Node child, boolean isLeftChild) { - if (parent == null) { - if (child == null) { - fRoot = new Node(0, NO_DELIM); - } else { - fRoot = child; - } - } else { - if (isLeftChild) { - parent.left = child; - } else { - parent.right = child; - } - } - if (child != null) { - child.parent = parent; - } - } - - /** - * A left rotation around parent, whose structural position is - * replaced by node. - * - * @param node the node moving up and left - * @param parent the node moving left and down - */ - private void singleLeftRotation(Node node, Node parent) { - rotateLeft(parent); - node.balance = 0; - parent.balance = 0; - } - - /** - * A right rotation around parent, whose structural position is - * replaced by node. - * - * @param node the node moving up and right - * @param parent the node moving right and down - */ - private void singleRightRotation(Node node, Node parent) { - rotateRight(parent); - node.balance = 0; - parent.balance = 0; - } - - /** - * A double left rotation, first rotating right around node, then - * left around parent. - * - * @param node the node that will be rotated right - * @param parent the node moving left and down - */ - private void rightLeftRotation(Node node, Node parent) { - Node child = node.left; - rotateRight(node); - rotateLeft(parent); - if (child.balance == 1) { - node.balance = 0; - parent.balance = -1; - child.balance = 0; - } else if (child.balance == 0) { - node.balance = 0; - parent.balance = 0; - } else if (child.balance == -1) { - node.balance = 1; - parent.balance = 0; - child.balance = 0; - } - } - - /** - * A double right rotation, first rotating left around node, then - * right around parent. - * - * @param node the node that will be rotated left - * @param parent the node moving right and down - */ - private void leftRightRotation(Node node, Node parent) { - Node child = node.right; - rotateLeft(node); - rotateRight(parent); - if (child.balance == -1) { - node.balance = 0; - parent.balance = 1; - child.balance = 0; - } else if (child.balance == 0) { - node.balance = 0; - parent.balance = 0; - } else if (child.balance == 1) { - node.balance = -1; - parent.balance = 0; - child.balance = 0; - } - } - - /** - * Inserts a line with the given length and delimiter after node. - * - * @param node the predecessor of the inserted node - * @param length the line length of the inserted node - * @param delimiter the delimiter of the inserted node - * @return the inserted node - */ - private Node insertAfter(Node node, int length, String delimiter) { - /* - * An insertion really shifts the key of all succeeding nodes. Hence we insert - * the added node between node and the successor of node. The added node becomes - * either the right child of the predecessor node, or the left child of the - * successor node. - */ - Node added = new Node(length, delimiter); - - if (node.right == null) { - setChild(node, added, false); - } else { - setChild(successorDown(node.right), added, true); - } - - // parent chain update - updateParentChain(added, length, 1); - updateParentBalanceAfterInsertion(added); - - return added; - } - - /** - * Updates the balance information in the parent chain of node until it reaches - * the root or finds a node whose balance violates the AVL constraint, which is - * the re-balanced. - * - * @param node the child of the first node that needs balance updating - */ - private void updateParentBalanceAfterInsertion(Node node) { - Node parent = node.parent; - while (parent != null) { - if (node == parent.left) { - parent.balance--; - } else { - parent.balance++; - } - - switch (parent.balance) { - case 1: - case -1: - node = parent; - parent = node.parent; - continue; - case -2: - rebalanceAfterInsertionLeft(node); - break; - case 2: - rebalanceAfterInsertionRight(node); - break; - case 0: - break; - default: - // if (ASSERT) - // Assert.isTrue(false); - } - return; - } - } - - /** - * Re-balances a node whose parent has a double positive balance. - * - * @param node the node to re-balance - */ - private void rebalanceAfterInsertionRight(Node node) { - Node parent = node.parent; - if (node.balance == 1) { - singleLeftRotation(node, parent); - } else if (node.balance == -1) { - rightLeftRotation(node, parent); - } else if (ASSERT) { - // Assert.isTrue(false); - } - } - - /** - * Re-balances a node whose parent has a double negative balance. - * - * @param node the node to re-balance - */ - private void rebalanceAfterInsertionLeft(Node node) { - Node parent = node.parent; - if (node.balance == -1) { - singleRightRotation(node, parent); - } else if (node.balance == 1) { - leftRightRotation(node, parent); - } else if (ASSERT) { - // Assert.isTrue(false); - } - } - - @Override - public final void replace(int offset, int length, String text) throws BadLocationException { - if (ASSERT) { - checkTree(); - } - - // Inlined nodeByOffset as we need both node and offset - int remaining = offset; - Node first = fRoot; - final int firstNodeOffset; - - while (true) { - if (first == null) { - fail(offset); - } - - if (remaining < first.offset) { - first = first.left; - } else { - remaining -= first.offset; - if (remaining < first.length || remaining == first.length && first.right == null) { // last line - firstNodeOffset = offset - remaining; - break; - } - remaining -= first.length; - first = first.right; - } - } - // Inline nodeByOffset end - // if (ASSERT) Assert.isTrue(first != null); - - Node last; - if (offset + length < firstNodeOffset + first.length) { - last = first; - } else { - last = nodeByOffset(offset + length); - } - // if (ASSERT) Assert.isTrue(last != null); - - int firstLineDelta = firstNodeOffset + first.length - offset; - if (first == last) { - replaceInternal(first, text, length, firstLineDelta); - } else { - replaceFromTo(first, last, text, length, firstLineDelta); - } - - // if (ASSERT) checkTree(); - } - - /** - * Replace happening inside a single line. - * - * @param node the affected node - * @param text the added text - * @param length the replace length, < firstLineDelta - * @param firstLineDelta the number of characters from the replacement offset to - * the end of node > length - */ - private void replaceInternal(Node node, String text, int length, int firstLineDelta) { - // 1) modification on a single line - - DelimiterInfo info = text == null ? null : nextDelimiterInfo(text, 0); - - if (info == null || info.delimiter == null) { - // a) trivial case: insert into a single node, no line mangling - int added = text == null ? 0 : text.length(); - updateLength(node, added - length); - } else { - // b) more lines to add between two chunks of the first node - // remember what we split off the first line - int remainder = firstLineDelta - length; - String remDelim = node.delimiter; - - // join the first line with the first added - int consumed = info.delimiterIndex + info.delimiterLength; - int delta = consumed - firstLineDelta; - updateLength(node, delta); - node.delimiter = info.delimiter; - - // Inline addlines start - info = nextDelimiterInfo(text, consumed); - while (info != null) { - int lineLen = info.delimiterIndex - consumed + info.delimiterLength; - node = insertAfter(node, lineLen, info.delimiter); - consumed += lineLen; - info = nextDelimiterInfo(text, consumed); - } - // Inline addlines end - - // add remaining chunk merged with last (incomplete) additional line - insertAfter(node, remainder + text.length() - consumed, remDelim); - } - } - - /** - * Replace spanning from one node to another. - * - * @param node the first affected node - * @param last the last affected node - * @param text the added text - * @param length the replace length, >= firstLineDelta - * @param firstLineDelta the number of characters removed from the replacement - * offset to the end of node, <= - * length - */ - private void replaceFromTo(Node node, Node last, String text, int length, int firstLineDelta) { - // 2) modification covers several lines - - // delete intermediate nodes - // TODO could be further optimized: replace intermediate lines with intermediate - // added lines - // to reduce re-balancing - Node successor = successor(node); - while (successor != last) { - length -= successor.length; - Node toDelete = successor; - successor = successor(successor); - updateLength(toDelete, -toDelete.length); - } - - DelimiterInfo info = text == null ? null : nextDelimiterInfo(text, 0); - - if (info == null || info.delimiter == null) { - int added = text == null ? 0 : text.length(); - - // join the two lines if there are no lines added - join(node, last, added - length); - - } else { - - // join the first line with the first added - int consumed = info.delimiterIndex + info.delimiterLength; - updateLength(node, consumed - firstLineDelta); - node.delimiter = info.delimiter; - length -= firstLineDelta; - - // Inline addLines start - info = nextDelimiterInfo(text, consumed); - while (info != null) { - int lineLen = info.delimiterIndex - consumed + info.delimiterLength; - node = insertAfter(node, lineLen, info.delimiter); - consumed += lineLen; - info = nextDelimiterInfo(text, consumed); - } - // Inline addLines end - - updateLength(last, text.length() - consumed - length); - } - } - - /** - * Joins two consecutive node lines, additionally adjusting the resulting length - * of the combined line by delta. The first node gets deleted. - * - * @param one the first node to join - * @param two the second node to join - * @param delta the delta to apply to the remaining single node - */ - private void join(Node one, Node two, int delta) { - int oneLength = one.length; - updateLength(one, -oneLength); - updateLength(two, oneLength + delta); - } - - /** - * Adjusts the length of a node by delta, also adjusting the parent - * chain of node. If the node's length becomes zero and is not the - * last (incomplete) node, it is deleted after the update. - * - * @param node the node to adjust - * @param delta the character delta to add to the node's length - */ - private void updateLength(Node node, int delta) { - // if (ASSERT) Assert.isTrue(node.length + delta >= 0); - - // update the node itself - node.length += delta; - - // check deletion - final int lineDelta; - boolean delete = node.length == 0 && node.delimiter != NO_DELIM; - if (delete) { - lineDelta = -1; - } else { - lineDelta = 0; - } - - // update parent chain - if (delta != 0 || lineDelta != 0) { - updateParentChain(node, delta, lineDelta); - } - - if (delete) { - delete(node); - } - } - - /** - * Updates the differential indices following the parent chain. All nodes from - * from.parent to the root are updated. - * - * @param node the child of the first node to update - * @param deltaLength the character delta - * @param deltaLines the line delta - */ - private void updateParentChain(Node node, int deltaLength, int deltaLines) { - updateParentChain(node, null, deltaLength, deltaLines); - } - - /** - * Updates the differential indices following the parent chain. All nodes from - * from.parent to to (exclusive) are updated. - * - * @param from the child of the first node to update - * @param to the first node not to update - * @param deltaLength the character delta - * @param deltaLines the line delta - */ - private void updateParentChain(Node from, Node to, int deltaLength, int deltaLines) { - Node parent = from.parent; - while (parent != to) { - // only update node if update comes from left subtree - if (from == parent.left) { - parent.offset += deltaLength; - parent.line += deltaLines; - } - from = parent; - parent = from.parent; - } - } - - /** - * Deletes a node from the tree, re-balancing it if necessary. The differential - * indices in the node's parent chain have to be updated in advance to calling - * this method. Generally, don't call delete directly, but call - * update_length(node, -node.length) to properly remove a node. - * - * @param node the node to delete. - */ - private void delete(Node node) { -// if (ASSERT) Assert.isTrue(node != null); -// if (ASSERT) Assert.isTrue(node.length == 0); - - Node parent = node.parent; - Node toUpdate; // the parent of the node that lost a child - boolean lostLeftChild; - boolean isLeftChild = parent == null || node == parent.left; - - if (node.left == null || node.right == null) { - // 1) node has one child at max - replace parent's pointer with the only child - // also handles the trivial case of no children - Node replacement = node.left == null ? node.right : node.left; - setChild(parent, replacement, isLeftChild); - toUpdate = parent; - lostLeftChild = isLeftChild; - // no updates to do - subtrees stay as they are - } else if (node.right.left == null) { - // 2a) node's right child has no left child - replace node with right child, - // giving node's - // left subtree to the right child - Node replacement = node.right; - setChild(parent, replacement, isLeftChild); - setChild(replacement, node.left, true); - replacement.line = node.line; - replacement.offset = node.offset; - replacement.balance = node.balance; - toUpdate = replacement; - lostLeftChild = false; -// } else if (node.left.right == null) { -// // 2b) symmetric case -// Node replacement= node.left; -// set_child(parent, replacement, isLeftChild); -// set_child(replacement, node.right, false); -// replacement.balance= node.balance; -// toUpdate= replacement; -// lostLeftChild= true; - } else { - // 3) hard case - replace node with its successor - Node successor = successor(node); - - // successor exists (otherwise node would not have right child, case 1) -// if (ASSERT) Assert.isNotNull(successor); -// // successor has no left child (a left child would be the real successor of node) -// if (ASSERT) Assert.isTrue(successor.left == null); -// if (ASSERT) Assert.isTrue(successor.line == 0); -// // successor is the left child of its parent (otherwise parent would be smaller and -// // hence the real successor) -// if (ASSERT) Assert.isTrue(successor == successor.parent.left); -// // successor is not a child of node (would have been covered by 2a) -// if (ASSERT) Assert.isTrue(successor.parent != node); - - toUpdate = successor.parent; - lostLeftChild = true; - - // update relative indices - updateParentChain(successor, node, -successor.length, -1); - - // delete successor from its current place - like 1) - setChild(toUpdate, successor.right, true); - - // move node's subtrees to its successor - setChild(successor, node.right, false); - setChild(successor, node.left, true); - - // replace node by successor in its parent - setChild(parent, successor, isLeftChild); - - // update the successor - successor.line = node.line; - successor.offset = node.offset; - successor.balance = node.balance; - } - - updateParentBalanceAfterDeletion(toUpdate, lostLeftChild); - } - - /** - * Updates the balance information in the parent chain of node. - * - * @param node the first node that needs balance updating - * @param wasLeftChild true if the deletion happened on - * node's left subtree, false if - * it occurred on node's right subtree - */ - private void updateParentBalanceAfterDeletion(Node node, boolean wasLeftChild) { - while (node != null) { - if (wasLeftChild) { - node.balance++; - } else { - node.balance--; - } - - Node parent = node.parent; - if (parent != null) { - wasLeftChild = node == parent.left; - } - - switch (node.balance) { - case 1: - case -1: - return; // done, no tree change - case -2: - if (rebalanceAfterDeletionRight(node.left)) { - return; - } - break; // propagate up - case 2: - if (rebalanceAfterDeletionLeft(node.right)) { - return; - } - break; // propagate up - case 0: - break; // propagate up - default: -// if (ASSERT) -// Assert.isTrue(false); - } - - node = parent; - } - } - - /** - * Re-balances a node whose parent has a double positive balance. - * - * @param node the node to re-balance - * @return true if the re-balancement leaves the height at - * node.parent constant, false if the height - * changed - */ - private boolean rebalanceAfterDeletionLeft(Node node) { - Node parent = node.parent; - if (node.balance == 1) { - singleLeftRotation(node, parent); - return false; - } else if (node.balance == -1) { - rightLeftRotation(node, parent); - return false; - } else if (node.balance == 0) { - rotateLeft(parent); - node.balance = -1; - parent.balance = 1; - return true; - } else { - // if (ASSERT) Assert.isTrue(false); - return true; - } - } - - /** - * Re-balances a node whose parent has a double negative balance. - * - * @param node the node to re-balance - * @return true if the re-balancement leaves the height at - * node.parent constant, false if the height - * changed - */ - private boolean rebalanceAfterDeletionRight(Node node) { - Node parent = node.parent; - if (node.balance == -1) { - singleRightRotation(node, parent); - return false; - } else if (node.balance == 1) { - leftRightRotation(node, parent); - return false; - } else if (node.balance == 0) { - rotateRight(parent); - node.balance = 1; - parent.balance = -1; - return true; - } else { - // if (ASSERT) Assert.isTrue(false); - return true; - } - } - - /** - * Returns the successor of a node, null if node is the last node. - * - * @param node a node - * @return the successor of node, null if there is - * none - */ - private Node successor(Node node) { - if (node.right != null) { - return successorDown(node.right); - } - - return successorUp(node); - } - - /** - * Searches the successor of node in its parent chain. - * - * @param node a node - * @return the first node in node's parent chain that is reached - * from its left subtree, null if there is none - */ - private Node successorUp(final Node node) { - Node child = node; - Node parent = child.parent; - while (parent != null) { - if (child == parent.left) { - return parent; - } - child = parent; - parent = child.parent; - } - // if (ASSERT) Assert.isTrue(node.delimiter == NO_DELIM); - return null; - } - - /** - * Searches the left-most node in a given subtree. - * - * @param node a node - * @return the left-most node in the given subtree - */ - private Node successorDown(Node node) { - Node child = node.left; - while (child != null) { - node = child; - child = node.left; - } - return node; - } - - /* miscellaneous */ - - /** - * Throws an exception. - * - * @param offset the illegal character or line offset that caused the exception - * @throws BadLocationException always - */ - private void fail(int offset) throws BadLocationException { - throw new BadLocationException(); - } - - /** - * Returns the information about the first delimiter found in the given text - * starting at the given offset. - * - * @param text the text to be searched - * @param offset the offset in the given text - * @return the information of the first found delimiter or null - */ - protected DelimiterInfo nextDelimiterInfo(String text, int offset) { - char ch; - int length = text.length(); - for (int i = offset; i < length; i++) { - - ch = text.charAt(i); - if (ch == '\r') { - - if (i + 1 < length) { - if (text.charAt(i + 1) == '\n') { - fDelimiterInfo.delimiter = DELIMITERS[2]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 2; - return fDelimiterInfo; - } - } - - fDelimiterInfo.delimiter = DELIMITERS[0]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 1; - return fDelimiterInfo; - - } else if (ch == '\n') { - - fDelimiterInfo.delimiter = DELIMITERS[1]; - fDelimiterInfo.delimiterIndex = i; - fDelimiterInfo.delimiterLength = 1; - return fDelimiterInfo; - } - } - - return null; - - } - - @Override - public final String getLineDelimiter(int line) throws BadLocationException { - Node node = nodeByLine(line); - return node.delimiter == NO_DELIM ? null : node.delimiter; - } - - @Override - public final int computeNumberOfLines(String text) { - int count = 0; - int start = 0; - DelimiterInfo delimiterInfo = nextDelimiterInfo(text, start); - while (delimiterInfo != null && delimiterInfo.delimiterIndex > -1) { - ++count; - start = delimiterInfo.delimiterIndex + delimiterInfo.delimiterLength; - delimiterInfo = nextDelimiterInfo(text, start); - } - return count; - } - - @Override - public final int getNumberOfLines() { - // TODO track separately? - Node node = fRoot; - int lines = 0; - while (node != null) { - lines += node.line + 1; - node = node.right; - } - return lines; - } - - @Override - public final int getNumberOfLines(int offset, int length) throws BadLocationException { - if (length == 0) { - return 1; - } - - int startLine = lineByOffset(offset); - int endLine = lineByOffset(offset + length); - - return endLine - startLine + 1; - } - - @Override - public final int getLineOffset(int line) throws BadLocationException { - return offsetByLine(line); - } - - @Override - public final int getLineLength(int line) throws BadLocationException { - Node node = nodeByLine(line); - return node.length; - } - - @Override - public final int getLineNumberOfOffset(int offset) throws BadLocationException { - return lineByOffset(offset); - } - - public final Position getPositionAt(int offset) throws BadLocationException { - Line l = getLineInformationOfOffset(offset); - int lineNumber = getLineNumberOfOffset(offset); - int character = offset - l.offset; - return new Position(lineNumber, character); - } - - @Override - public int getOffsetAt(Position position) throws BadLocationException { - int line = position.getLine(); - Line l = getLineInformation(line); - - if (line < 0/* || line > lines */) { - throw new BadLocationException("The line value, {" + line + "}, is out of bounds."); - } - - int lineOffset = l.offset; - int lineLength = l.delimiter != null ? l.length - l.delimiter.length() : l.length; - -// int lineOffset = -1; -// int lineLength = -1; -// if (lines == 0) { -// lineOffset = 0; -// lineLength = 0; -// } else { -// if (line == lines) { -// Line l = fLines.get(line - 1); -// lineOffset = l.offset + l.length; -// lineLength = 0; -// } else { -// Line l = fLines.get(line); -// lineOffset = l.offset; -// lineLength = l.delimiter != null ? l.length - l.delimiter.length() : l.length; -// } -// } - int character = position.getCharacter(); - int offset = lineOffset + character; - int endLineOffset = lineOffset + lineLength; - if (offset > endLineOffset) { - throw new BadLocationException( - "The character value, {" + character + "} of the line" + line + "}, is out of bounds."); - } - return offset; - - } - - @Override - public final Line getLineInformationOfOffset(final int offset) throws BadLocationException { - // Inline nodeByOffset start as we need both node and offset - int remaining = offset; - Node node = fRoot; - final int lineOffset; - - while (true) { - if (node == null) { - fail(offset); - } - - if (remaining < node.offset) { - node = node.left; - } else { - remaining -= node.offset; - if (remaining < node.length || remaining == node.length && node.right == null) { // last line - lineOffset = offset - remaining; - break; - } - remaining -= node.length; - node = node.right; - } - } - // Inline nodeByOffset end - return new Line(lineOffset, node.pureLength()); - } - - @Override - public final Line getLineInformation(int line) throws BadLocationException { - try { - // Inline nodeByLine start - int remaining = line; - int offset = 0; - Node node = fRoot; - - while (true) { - if (node == null) { - fail(line); - } - - if (remaining == node.line) { - offset += node.offset; - break; - } - if (remaining < node.line) { - node = node.left; - } else { - remaining -= node.line + 1; - offset += node.offset + node.length; - node = node.right; - } - } - // Inline nodeByLine end - return new Line(offset, node.pureLength()); - } catch (BadLocationException x) { - /* - * FIXME: this really strange behavior is mandated by the previous line tracker - * implementation and included here for compatibility. See - * LineTrackerTest3#testFunnyLastLineCompatibility(). - */ - if (line > 0 && line == getNumberOfLines()) { - line = line - 1; - // Inline nodeByLine start - int remaining = line; - int offset = 0; - Node node = fRoot; - - while (true) { - if (node == null) { - fail(line); - } - - if (remaining == node.line) { - offset += node.offset; - break; - } - if (remaining < node.line) { - node = node.left; - } else { - remaining -= node.line + 1; - offset += node.offset + node.length; - node = node.right; - } - } - Node last = node; - // Inline nodeByLine end - if (last.length > 0) { - return new Line(offset + last.length, 0); - } - } - throw x; - } - } - - @Override - public final void set(String text) { - fRoot = new Node(0, NO_DELIM); - try { - replace(0, 0, text); - } catch (BadLocationException x) { - throw new InternalError(); - } - } - - @Override - public String toString() { - int depth = computeDepth(fRoot); - int WIDTH = 30; - int leaves = (int) Math.pow(2, depth - 1); - int width = WIDTH * leaves; - String empty = "."; //$NON-NLS-1$ - - List roots = new LinkedList<>(); - roots.add(fRoot); - StringBuilder buf = new StringBuilder((width + 1) * depth); // see Bug 137688 - int indents = leaves; - char[] space = new char[leaves * WIDTH / 2]; - Arrays.fill(space, ' '); - for (int d = 0; d < depth; d++) { - // compute indent - indents /= 2; - int spaces = Math.max(0, indents * WIDTH - WIDTH / 2); - // print nodes - for (ListIterator it = roots.listIterator(); it.hasNext();) { - // pad before - buf.append(space, 0, spaces); - - Node node = it.next(); - String box; - // replace the node with its children - if (node == null) { - it.add(null); - box = empty; - } else { - it.set(node.left); - it.add(node.right); - box = node.toString(); - } - - // draw the node, pad to WIDTH - int pad_left = (WIDTH - box.length() + 1) / 2; - int pad_right = WIDTH - box.length() - pad_left; - buf.append(space, 0, pad_left); - buf.append(box); - buf.append(space, 0, pad_right); - - // pad after - buf.append(space, 0, spaces); - } - - buf.append('\n'); - } - - return buf.toString(); - } - - /** - * Recursively computes the depth of the tree. Only used by {@link #toString()}. - * - * @param root the subtree to compute the depth of, may be null - * @return the depth of the given tree, 0 if it is null - */ - private byte computeDepth(Node root) { - if (root == null) { - return 0; - } - - return (byte) (Math.max(computeDepth(root.left), computeDepth(root.right)) + 1); - } - - /** - * Debug-only method that checks the tree structure and the differential - * offsets. - */ - private void checkTree() { - checkTreeStructure(fRoot); - - try { - checkTreeOffsets(nodeByOffset(0), new int[] { 0, 0 }, null); - } catch (BadLocationException x) { - throw new AssertionError(); - } - } - - /** - * Debug-only method that validates the tree structure below node. - * I.e. it checks whether all parent/child pointers are consistent and whether - * the AVL balance information is correct. - * - * @param node the node to validate - * @return the depth of the tree under node - */ - private byte checkTreeStructure(Node node) { - if (node == null) { - return 0; - } - - byte leftDepth = checkTreeStructure(node.left); - byte rightDepth = checkTreeStructure(node.right); -// Assert.isTrue(node.balance == rightDepth - leftDepth); -// Assert.isTrue(node.left == null || node.left.parent == node); -// Assert.isTrue(node.right == null || node.right.parent == node); - - return (byte) (Math.max(rightDepth, leftDepth) + 1); - } - - /** - * Debug-only method that checks the differential offsets of the tree, starting - * at node and continuing until last. - * - * @param node the first Node to check, may be null - * @param offLen an array of length 2, with offLen[0] the expected - * offset of node and offLen[1] the - * expected line of node - * @param last the last Node to check, may be null - * @return an int[] of length 2, with the first element being the - * character length of node's subtree, and the second - * element the number of lines in node's subtree - */ - private int[] checkTreeOffsets(Node node, int[] offLen, Node last) { - if (node == last) { - return offLen; - } - - // Assert.isTrue(node.offset == offLen[0]); - // Assert.isTrue(node.line == offLen[1]); - - if (node.right != null) { - int[] result = checkTreeOffsets(successorDown(node.right), new int[2], node); - offLen[0] += result[0]; - offLen[1] += result[1]; - } - - offLen[0] += node.length; - offLen[1]++; - return checkTreeOffsets(node.parent, offLen, last); - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetContext.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetContext.java deleted file mode 100644 index c8fe1c0cf..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetContext.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -import java.util.Map; - -/** - * Snippet context used to filter the snippet. - * - * @author Angelo ZERR - * - * @param the value type waited by the snippet context. - */ -public interface ISnippetContext { - - /** - * Return true if the given value match the snippet context and false otherwise. - * - * @param value the value to check. - * @return true if the given value match the snippet context and false - * otherwise. - */ - boolean isMatch(T value, Map model); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetRegistryLoader.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetRegistryLoader.java deleted file mode 100644 index e832b1eb5..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISnippetRegistryLoader.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -/** - * Loader used to load snippets in a given registry for a language id. - * - * @author Angelo ZERR - * - */ -public interface ISnippetRegistryLoader { - - /** - * Register snippets in the given snippet registry. - * - * @param registry - * @throws Exception - */ - void load(SnippetRegistry registry) throws Exception; - - /** - * Returns the language id and null otherwise. - * - * @return the language id and null otherwise. - */ - default String getLanguageId() { - return null; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISuffixPositionProvider.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISuffixPositionProvider.java deleted file mode 100644 index 835c94f97..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/ISuffixPositionProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -import org.eclipse.lsp4j.Position; - -/** - * Suffix position provider API. - * - * @author Angelo ZERR - * - */ -public interface ISuffixPositionProvider { - - /** - * Returns the suffix position provider of the given sufix and null - * otherwise. - * - * @param suffix - * @return the suffix position provider of the given sufix and null - * otherwise. - */ - Position findSuffixPosition(String suffix); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/Snippet.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/Snippet.java deleted file mode 100644 index 46a625b7f..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/Snippet.java +++ /dev/null @@ -1,118 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -import java.util.List; -import java.util.Map; -import java.util.function.BiPredicate; - -/** - * Snippet description (like vscode snippet). - * - * @author Angelo ZERR - * - */ -public class Snippet { - - private String label; - - private List prefixes; - - private String suffix; - - private List body; - - private String description; - - private String scope; - - private String sortText; - - private ISnippetContext context; - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public List getPrefixes() { - return prefixes; - } - - public void setPrefixes(List prefixes) { - this.prefixes = prefixes; - } - - public String getSuffix() { - return suffix; - } - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - public List getBody() { - return body; - } - - public void setBody(List body) { - this.body = body; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } - - public String getSortText() { - return sortText; - } - - public void setSortText(String sortText) { - this.sortText = sortText; - } - - public ISnippetContext getContext() { - return context; - } - - public void setContext(ISnippetContext context) { - this.context = context; - } - - public boolean hasContext() { - return getContext() != null; - } - - public boolean match(BiPredicate, Map> contextFilter, - Map model) { - if (!hasContext()) { - return true; - } - return contextFilter.test(getContext(), model); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetDeserializer.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetDeserializer.java deleted file mode 100644 index 8a07f0f7e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetDeserializer.java +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.lemminx.utils.StringUtils; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.TypeAdapter; - -/** - * GSON deserializer to build Snippet from vscode JSON snippet. - * - * @author Angelo ZERR - * - */ -class SnippetDeserializer implements JsonDeserializer { - - private static final String PREFIX_ELT = "prefix"; - private static final String SUFFIX_ELT = "suffix"; - private static final String DESCRIPTION_ELT = "description"; - private static final String LABEL_ELT = "label"; - private static final String SCOPE_ELT = "scope"; - private static final String SORTTEXT_ELT = "sortText"; - private static final String BODY_ELT = "body"; - private static final String CONTEXT_ELT = "context"; - - private final TypeAdapter> contextDeserializer; - - public SnippetDeserializer(TypeAdapter> contextDeserializer) { - this.contextDeserializer = contextDeserializer; - } - - @Override - public Snippet deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - Snippet snippet = new Snippet(); - JsonObject snippetObj = json.getAsJsonObject(); - - // prefix - List prefixes = new ArrayList<>(); - JsonElement prefixElt = snippetObj.get(PREFIX_ELT); - if (prefixElt != null) { - if (prefixElt.isJsonArray()) { - JsonArray prefixArray = (JsonArray) prefixElt; - prefixArray.forEach(elt -> { - prefixes.add(elt.getAsString()); - }); - } else if (prefixElt.isJsonPrimitive()) { - prefixes.add(prefixElt.getAsString()); - } - } - snippet.setPrefixes(prefixes); - // by default label is the first prefix - if (!prefixes.isEmpty()) { - snippet.setLabel(prefixes.get(0)); - } - - // suffix - JsonElement suffixElt = snippetObj.get(SUFFIX_ELT); - if (suffixElt != null) { - String suffix = suffixElt.getAsString(); - snippet.setSuffix(suffix); - } - - // body - List body = new ArrayList<>(); - JsonElement bodyElt = snippetObj.get(BODY_ELT); - if (bodyElt != null) { - if (bodyElt.isJsonArray()) { - JsonArray bodyArray = (JsonArray) bodyElt; - bodyArray.forEach(elt -> { - body.add(elt.getAsString()); - }); - } else if (bodyElt.isJsonPrimitive()) { - body.add(bodyElt.getAsString()); - } - } - snippet.setBody(body); - - // description - JsonElement descriptionElt = snippetObj.get(DESCRIPTION_ELT); - if (descriptionElt != null) { - String description = descriptionElt.getAsString(); - snippet.setDescription(description); - } - - // label - JsonElement labelElt = snippetObj.get(LABEL_ELT); - if (labelElt != null) { - String label = labelElt.getAsString(); - if (label.contains("$")) { - if (!StringUtils.isEmpty(snippet.getDescription())) { - label = label.replace("$description", snippet.getDescription()); - } - if (!snippet.getPrefixes().isEmpty()) { - label = label.replace("$prefix", snippet.getPrefixes().get(0)); - } - } - snippet.setLabel(label); - } - - // scope - JsonElement scopeElt = snippetObj.get(SCOPE_ELT); - if (scopeElt != null) { - String scope = scopeElt.getAsString(); - snippet.setScope(scope); - } - - // sortText - JsonElement sortTextElt = snippetObj.get(SORTTEXT_ELT); - if (sortTextElt != null) { - String sortText = sortTextElt.getAsString(); - snippet.setSortText(sortText); - } - - // context - if (contextDeserializer != null) { - JsonElement contextElt = snippetObj.get(CONTEXT_ELT); - if (contextElt != null) { - ISnippetContext snippetContext = contextDeserializer.fromJsonTree(contextElt); - snippet.setContext(snippetContext); - } - } - - return snippet; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetRegistry.java b/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetRegistry.java deleted file mode 100644 index 68f204bdb..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/commons/snippets/SnippetRegistry.java +++ /dev/null @@ -1,397 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.commons.snippets; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.ServiceLoader; -import java.util.function.BiPredicate; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.CompletionItemKind; -import org.eclipse.lsp4j.InsertTextFormat; -import org.eclipse.lsp4j.MarkupContent; -import org.eclipse.lsp4j.MarkupKind; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.TextEdit; -import org.eclipse.lsp4j.jsonrpc.messages.Either; - -import com.google.gson.GsonBuilder; -import com.google.gson.JsonIOException; -import com.google.gson.JsonSyntaxException; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; - -/** - * A registry for snippets which uses the same format than vscode snippet. - * - * @author Angelo ZERR - * - */ -public class SnippetRegistry { - - private static final Logger LOGGER = Logger.getLogger(SnippetRegistry.class.getName()); - - private final List snippets; - - public SnippetRegistry() { - this(null, true); - } - - /** - * Snippet registry for a given language id. - * - * @param languageId the language id and null otherwise. - * @param loadDefault true if default snippets from SPI must be loaded and false - * otherwise. - */ - public SnippetRegistry(String languageId, boolean loadDefault) { - snippets = new ArrayList<>(); - // Load snippets from SPI - if (loadDefault) { - ServiceLoader loaders = ServiceLoader.load(ISnippetRegistryLoader.class); - loaders.forEach(loader -> { - if (Objects.equals(languageId, loader.getLanguageId())) { - try { - loader.load(this); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while consumming snippet loader " + loader.getClass().getName(), - e); - } - } - }); - } - } - - /** - * Register the given snippet. - * - * @param snippet the snippet to register. - */ - public void registerSnippet(Snippet snippet) { - snippets.add(snippet); - } - - /** - * Register the snippets from the given JSON input stream. - * - * @param in the JSON input stream which declares snippets with vscode snippet - * format. - * @throws IOException - */ - public void registerSnippets(InputStream in) throws IOException { - registerSnippets(in, null, null); - } - - /** - * Register the snippets from the given JSON stream with a context. - * - * @param in the JSON input stream which declares snippets with - * vscode snippet format. - * @param contextDeserializer the GSON context deserializer used to create Java - * context. - * @throws IOException - */ - public void registerSnippets(InputStream in, TypeAdapter> contextDeserializer) - throws IOException { - registerSnippets(in, null, contextDeserializer); - } - - /** - * Register the snippets from the given JSON stream with a context. - * - * @param in the JSON input stream which declares snippets with - * vscode snippet format. - * @param defaultContext the default context. - * @throws IOException - */ - public void registerSnippets(InputStream in, ISnippetContext defaultContext) throws IOException { - registerSnippets(in, defaultContext, null); - } - - /** - * Register the snippets from the given JSON stream with a context. - * - * @param in the JSON input stream which declares snippets with - * vscode snippet format. - * @param defaultContext the default context. - * @param contextDeserializer the GSON context deserializer used to create Java - * context. - * @throws IOException - */ - public void registerSnippets(InputStream in, ISnippetContext defaultContext, - TypeAdapter> contextDeserializer) throws IOException { - registerSnippets(new InputStreamReader(in, StandardCharsets.UTF_8.name()), defaultContext, contextDeserializer); - } - - /** - * Register the snippets from the given JSON reader. - * - * @param in the JSON reader which declares snippets with vscode snippet format. - * @throws IOException - */ - public void registerSnippets(Reader in) throws IOException { - registerSnippets(in, null, null); - } - - /** - * Register the snippets from the given JSON reader with a context. - * - * @param in the JSON reader which declares snippets with - * vscode snippet format. - * @param contextDeserializer the GSON context deserializer used to create Java - * context. - * @throws IOException - */ - public void registerSnippets(Reader in, TypeAdapter> contextDeserializer) - throws IOException { - registerSnippets(in, null, contextDeserializer); - } - - /** - * Register the snippets from the given JSON stream with a context. - * - * @param in the JSON reader which declares snippets with vscode - * snippet format. - * @param defaultContext the default context. - * @throws IOException - */ - public void registerSnippets(Reader in, ISnippetContext defaultContext) throws IOException { - registerSnippets(in, defaultContext, null); - } - - /** - * Register the snippets from the given JSON stream with a context. - * - * @param in the JSON reader which declares snippets with - * vscode snippet format. - * @param defaultContext the default context. - * @param contextDeserializer the GSON context deserializer used to create Java - * context. - * @throws IOException - */ - public void registerSnippets(Reader in, ISnippetContext defaultContext, - TypeAdapter> contextDeserializer) throws IOException { - JsonReader reader = new JsonReader(in); - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - Snippet snippet = createSnippet(reader, contextDeserializer); - if (snippet.getDescription() == null) { - snippet.setDescription(name); - } - if (snippet.getContext() == null) { - snippet.setContext(defaultContext); - } - registerSnippet(snippet); - } - reader.endObject(); - } - - private static Snippet createSnippet(JsonReader reader, - TypeAdapter> contextDeserializer) throws JsonIOException, JsonSyntaxException { - GsonBuilder builder = new GsonBuilder(); - builder.registerTypeAdapter(Snippet.class, new SnippetDeserializer(contextDeserializer)); - return builder.create().fromJson(reader, Snippet.class); - } - - /** - * Returns all snippets. - * - * @return all snippets. - */ - public List getSnippets() { - return snippets; - } - - /** - * Returns the snippet completion items according to the context filter. - * - * @param replaceRange the replace range. - * @param lineDelimiter the line delimiter. - * @param canSupportMarkdown true if markdown is supported to generate - * documentation and false otherwise. - * @param contextFilter the context filter. - * @return the snippet completion items according to the context filter. - */ - public List getCompletionItems(Range replaceRange, String lineDelimiter, boolean canSupportMarkdown, - boolean snippetsSupported, BiPredicate, Map> contextFilter, - ISuffixPositionProvider suffixProvider) { - if (replaceRange == null) { - return Collections.emptyList(); - } - Map model = new HashMap<>(); - return getSnippets().stream().filter(snippet -> { - return snippet.match(contextFilter, model); - }).map(snippet -> { - CompletionItem item = new CompletionItem(); - item.setLabel(snippet.getLabel()); - String insertText = getInsertText(snippet, model, !snippetsSupported, lineDelimiter); - item.setKind(CompletionItemKind.Snippet); - item.setDocumentation( - Either.forRight(createDocumentation(snippet, model, canSupportMarkdown, lineDelimiter))); - String prefix = snippet.getPrefixes().get(0); - item.setFilterText(prefix); - item.setDetail(snippet.getDescription()); - Range range = replaceRange; - if (!StringUtils.isEmpty(snippet.getSuffix()) && suffixProvider != null) { - Position end = suffixProvider.findSuffixPosition(snippet.getSuffix()); - if (end != null) { - range = new Range(replaceRange.getStart(), end); - } - } - item.setTextEdit(Either.forLeft(new TextEdit(range, insertText))); - item.setInsertTextFormat(InsertTextFormat.Snippet); - item.setSortText(snippet.getSortText()); - return item; - - }).collect(Collectors.toList()); - } - - private static MarkupContent createDocumentation(Snippet snippet, Map model, - boolean canSupportMarkdown, String lineDelimiter) { - StringBuilder doc = new StringBuilder(); - if (canSupportMarkdown) { - doc.append(System.lineSeparator()); - doc.append("```"); - String scope = snippet.getScope(); - if (scope != null) { - doc.append(scope); - } - doc.append(System.lineSeparator()); - } - String insertText = getInsertText(snippet, model, true, lineDelimiter); - doc.append(insertText); - if (canSupportMarkdown) { - doc.append(System.lineSeparator()); - doc.append("```"); - doc.append(System.lineSeparator()); - } - return new MarkupContent(canSupportMarkdown ? MarkupKind.MARKDOWN : MarkupKind.PLAINTEXT, doc.toString()); - } - - private static String getInsertText(Snippet snippet, Map model, boolean replace, - String lineDelimiter) { - StringBuilder text = new StringBuilder(); - int i = 0; - List body = snippet.getBody(); - if (body != null) { - for (String bodyLine : body) { - if (i > 0) { - text.append(lineDelimiter); - } - bodyLine = merge(bodyLine, model, replace); - text.append(bodyLine); - i++; - } - } - return text.toString(); - } - - private static String merge(String line, Map model, boolean replace) { - return replace(line, 0, model, replace, null); - } - - private static String replace(String line, int offset, Map model, boolean replace, - StringBuilder newLine) { - int dollarIndex = line.indexOf("$", offset); - if (dollarIndex == -1 || dollarIndex == line.length() - 1) { - if (newLine == null) { - return line; - } - newLine.append(line, offset, line.length()); - return newLine.toString(); - } - if (newLine == null) { - newLine = new StringBuilder(); - } - char next = line.charAt(dollarIndex + 1); - if (Character.isDigit(next)) { - if (replace) { - newLine.append(line, offset, dollarIndex); - } - int lastDigitOffset = dollarIndex + 1; - while (Character.isDigit(line.charAt(lastDigitOffset))) { - lastDigitOffset++; - } - if (!replace) { - newLine.append(line, offset, lastDigitOffset); - } - return replace(line, lastDigitOffset, model, replace, newLine); - } else if (next == '{') { - int startExpr = dollarIndex; - int endExpr = line.indexOf("}", startExpr); - if (endExpr == -1) { - // Should never occur - return line; - } - newLine.append(line, offset, startExpr); - // Parameter - int startParam = startExpr + 2; - int endParam = endExpr; - boolean startsWithNumber = true; - boolean onlyNumber = true; - for (int i = startParam; i < endParam; i++) { - char ch = line.charAt(i); - if (Character.isDigit(ch)) { - startsWithNumber = true; - } else { - onlyNumber = false; - if (ch == ':') { - - if (startsWithNumber) { - startParam = i + 1; - } - break; - } else if (ch == '|') { - if (startsWithNumber) { - startParam = i + 1; - int index = line.indexOf(',', startExpr); - if (index != -1) { - endParam = index; - } - } - break; - } else { - break; - } - } - } - String paramName = line.substring(startParam, endParam); - if (model.containsKey(paramName)) { - paramName = model.get(paramName); - } else if (!replace) { - paramName = line.substring(startExpr, endExpr + 1); - } - if (!(replace && onlyNumber)) { - newLine.append(paramName); - } - return replace(line, endExpr + 1, model, replace, newLine); - } - return line; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/customservice/ActionableNotification.java b/lemminx/src/main/java/org/eclipse/lemminx/customservice/ActionableNotification.java deleted file mode 100644 index af5603e54..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/customservice/ActionableNotification.java +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016-2017 Red Hat Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.lemminx.customservice; - -import java.util.List; - -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.MessageType; -import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; - -import com.google.gson.annotations.Expose; -import com.google.gson.annotations.SerializedName; - -/** - * An ActionableNotification class. - * - * An instance of this class is sent to the client as a parameter - * for the xml/actionableNotification notification. - * - * See {@link org.eclipse.lemminx.customservice.XMLLanguageClientAPI} - */ -public class ActionableNotification { - - /** - * The message type. See {@link MessageType}. - * - */ - @SerializedName("severity") - @Expose - private MessageType severity; - /** - * The actual message - * - */ - @SerializedName("message") - @Expose - private String message; - - /** - * Optional data - * - */ - @SerializedName("data") - @Expose - private Object data; - - - /** - * Optional commands - * - */ - @SerializedName("commands") - @Expose - private List commands; - - /** - * The message severity. See {@link MessageType}. - * - * @return - * The severity - */ - public MessageType getSeverity() { - return severity; - } - - /** - * The message severity. See {@link MessageType}. - * - * @param severity - * The message severity - */ - public void setSeverity(MessageType severity) { - this.severity = severity; - } - - public ActionableNotification withSeverity(MessageType severity) { - this.severity = severity; - return this; - } - - /** - * The actual message - * - * @return - * The message - */ - public String getMessage() { - return message; - } - - /** - * The actual message - * - * @param message - * The message - */ - public void setMessage(String message) { - this.message = message; - } - - public ActionableNotification withMessage(String message) { - this.message = message; - return this; - } - - /** - * @return the data - */ - public Object getData() { - return data; - } - - /** - * @param data the data to set - */ - public void setData(Object data) { - this.data = data; - } - - public ActionableNotification withData(Object data) { - this.data = data; - return this; - } - - /** - * @return the commands - */ - public List getCommands() { - return commands; - } - - /** - * @param commands the commands to set - */ - public void setCommands(List commands) { - this.commands = commands; - } - - public ActionableNotification withCommands(List commands) { - this.commands = commands; - return this; - } - - @Override - public String toString() { - return MessageJsonHandler.toString(this); - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/customservice/AutoCloseTagResponse.java b/lemminx/src/main/java/org/eclipse/lemminx/customservice/AutoCloseTagResponse.java deleted file mode 100644 index cd8249bc7..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/customservice/AutoCloseTagResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 Red Hat Inc. and others. All rights reserved. This program - * and the accompanying materials which accompanies this distribution, and is - * available at http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: Red Hat Inc. - initial API and implementation - *******************************************************************************/ - -package org.eclipse.lemminx.customservice; - -import org.eclipse.lsp4j.Range; - -public class AutoCloseTagResponse { - public String snippet; - public Range range; - - public AutoCloseTagResponse(String snippet, Range range) { - this.snippet = snippet; - this.range = range; - } - - public AutoCloseTagResponse(String snippet) { - this.snippet = snippet; - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageClientAPI.java b/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageClientAPI.java deleted file mode 100644 index c03a21066..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageClientAPI.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2020 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.customservice; - -import java.util.concurrent.CompletableFuture; - -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.services.JsonNotification; -import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; -import org.eclipse.lsp4j.jsonrpc.services.JsonSegment; -import org.eclipse.lsp4j.services.LanguageClient; - -/** - * XML language client API. - * - */ -@JsonSegment("xml") -public interface XMLLanguageClientAPI extends LanguageClient { - - /** - * Notification to be sent to the client with a list of commands - * - * @param command - */ - @JsonNotification("actionableNotification") - default void actionableNotification(ActionableNotification command) { - throw new UnsupportedOperationException(); - } - - /** - * Executes the command on the client which gives an opportunity to execute a - * command registered by a different Language Server - * - * @param params command execution parameters - * @return the result of the command execution - */ - @JsonRequest("executeClientCommand") - default CompletableFuture executeClientCommand(ExecuteCommandParams params) { - throw new UnsupportedOperationException(); - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageServerAPI.java b/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageServerAPI.java deleted file mode 100644 index 453041dc6..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/customservice/XMLLanguageServerAPI.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.customservice; - -import java.util.concurrent.CompletableFuture; - -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.TextDocumentPositionParams; -import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; -import org.eclipse.lsp4j.jsonrpc.services.JsonSegment; - -/** - * XML custom services. - * - */ -@JsonSegment("xml") -public interface XMLLanguageServerAPI { - - @JsonRequest - CompletableFuture closeTag(TextDocumentPositionParams params); - - @JsonRequest - CompletableFuture matchingTagPosition(TextDocumentPositionParams params); -} - - diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMAttr.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMAttr.java deleted file mode 100644 index 23edb5b6e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMAttr.java +++ /dev/null @@ -1,412 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import java.util.List; - -import org.eclipse.lemminx.utils.StringUtils; -import org.w3c.dom.DOMException; -import org.w3c.dom.Node; -import org.w3c.dom.TypeInfo; - -/** - * An attribute node. - * - */ -public class DOMAttr extends DOMNode implements org.w3c.dom.Attr { - - private final String name; - - private final DOMNode nodeAttrName; - - private DOMNode nodeAttrValue; - - private String quotelessValue;// Value without quotes - - private String originalValue;// Exact value from document - - private final DOMNode ownerElement; - - private boolean hasDelimiter; // has '=' - - public static final String XMLNS_ATTR = "xmlns"; - public static final String XMLNS_NO_DEFAULT_ATTR = "xmlns:"; - - class AttrNameOrValue extends DOMNode { - - public AttrNameOrValue(int start, int end) { - super(start, end); - } - - @Override - public String getNodeName() { - return null; - } - - @Override - public short getNodeType() { - return -1; - } - - public DOMAttr getOwnerAttr() { - return DOMAttr.this; - } - - @Override - public DOMNode getParentNode() { - return DOMAttr.this; - } - - @Override - public DOMDocument getOwnerDocument() { - return getOwnerAttr().getOwnerDocument(); - } - } - - public DOMAttr(String name, DOMNode ownerElement) { - this(name, -1, -1, ownerElement); - } - - public DOMAttr(String name, int start, int end, DOMNode ownerElement) { - super(-1, -1); - this.name = name; - this.nodeAttrName = start != -1 ? new AttrNameOrValue(start, end) : null; - this.ownerElement = ownerElement; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.ATTRIBUTE_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return getName(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#getName() - */ - @Override - public String getName() { - return name; - } - - @Override - public String getNodeValue() throws DOMException { - return getValue(); - } - - @Override - public String getLocalName() { - int colonIndex = name.indexOf(":"); - if (colonIndex > 0) { - return name.substring(colonIndex + 1); - } - return name; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#getOwnerElement() - */ - public DOMElement getOwnerElement() { - return ownerElement.isElement() ? (DOMElement) ownerElement : null; - } - - @Override - public DOMDocument getOwnerDocument() { - return ownerElement != null ? ownerElement.getOwnerDocument() : null; - } - - /* - * - * Returns the attribute's value without quotes. - */ - @Override - public String getValue() { - return quotelessValue; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#getSchemaTypeInfo() - */ - @Override - public TypeInfo getSchemaTypeInfo() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#getSpecified() - */ - @Override - public boolean getSpecified() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#isId() - */ - @Override - public boolean isId() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Attr#setValue(java.lang.String) - */ - @Override - public void setValue(String value) throws DOMException { - setValue(value, -1, -1); - } - - public DOMNode getNodeAttrName() { - return nodeAttrName; - } - - public void setDelimiter(boolean hasDelimiter) { - this.hasDelimiter = hasDelimiter; - } - - public boolean hasDelimiter() { - return this.hasDelimiter; - } - - /** - * Get original attribute value from the document. - * - * This will include quotations (", '). - * - * @return attribute value with quotations if it had them. - */ - public String getOriginalValue() { - return originalValue; - } - - public void setValue(String value, int start, int end) { - this.originalValue = value; - this.quotelessValue = StringUtils.convertToQuotelessValue(value); - this.nodeAttrValue = start != -1 ? new AttrNameOrValue(start, end) : null; - } - - public DOMNode getNodeAttrValue() { - return nodeAttrValue; - } - - public void setNodeAttrValue(DOMNode nodeAttrValue) { - this.nodeAttrValue = nodeAttrValue; - } - - public boolean valueContainsOffset(int offset) { - return nodeAttrValue != null && offset >= nodeAttrValue.getStart() && offset < nodeAttrValue.getEnd(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getPrefix() - */ - @Override - public String getPrefix() { - String name = getName(); - if (name == null) { - return null; - } - String prefix = null; - int index = name.indexOf(":"); //$NON-NLS-1$ - if (index != -1) { - prefix = name.substring(0, index); - } - return prefix; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNamespaceURI() - */ - @Override - public String getNamespaceURI() { - if (ownerElement == null || ownerElement.getNodeType() != Node.ELEMENT_NODE) { - return null; - } - String prefix = getPrefix(); - // Try to get xmlns attribute from the element - return ((DOMElement) ownerElement).getNamespaceURI(prefix); - } - - /** - * Returns true if attribute name is a xmlns attribute and false otherwise. - * - * @param attributeName - * @return true if attribute name is a xmlns attribute and false otherwise. - */ - public boolean isXmlns() { - return isXmlns(name); - } - - public static boolean isXmlns(String attributeName) { - return attributeName.startsWith(XMLNS_ATTR); - } - - /** - * Returns true if attribute name is the default xmlns attribute and false - * otherwise. - * - * @param attributeName - * @return true if attribute name is the default xmlns attribute and false - * otherwise. - */ - public boolean isDefaultXmlns() { - return isDefaultXmlns(name); - } - - public static boolean isDefaultXmlns(String attributeName) { - return attributeName.equals(XMLNS_ATTR); - } - - public String extractPrefixFromXmlns() { - if (isDefaultXmlns()) { - return name.substring(XMLNS_ATTR.length(), name.length()); - } - return name.substring(XMLNS_NO_DEFAULT_ATTR.length(), name.length()); - } - - /** - * Returns the prefix if the given URI matches this attributes value. - * - * If the URI doesnt match, null is returned. - * - * @param uri - * @return - */ - public String getPrefixIfMatchesURI(String uri) { - if (isXmlns()) { - if (quotelessValue != null && quotelessValue.equals(uri)) { - if (isDefaultXmlns()) { - // xmlns="http://" - return null; - } - // xmlns:xxx="http://" - return extractPrefixFromXmlns(); - } - } - return null; - } - - /** - * Returns true if attribute name is the no default xmlns attribute and false - * otherwise. - * - * @param attributeName - * @return true if attribute name is the no default xmlns attribute and false - * otherwise. - */ - public boolean isNoDefaultXmlns() { - return isNoDefaultXmlns(name); - } - - public static boolean isNoDefaultXmlns(String attributeName) { - return attributeName.startsWith(XMLNS_NO_DEFAULT_ATTR); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNextSibling() - */ - @Override - public DOMNode getNextSibling() { - DOMNode parentNode = getOwnerElement(); - if (parentNode == null) { - return null; - } - List children = parentNode.getAttributeNodes(); - int nextIndex = children.indexOf(this) + 1; - return nextIndex < children.size() ? children.get(nextIndex) : null; - } - - public boolean isIncluded(int offset) { - return DOMNode.isIncluded(getStart(), getEnd(), offset); - } - - @Override - public int getStart() { - return nodeAttrName.start; - } - - @Override - public int getEnd() { - return nodeAttrValue != null ? nodeAttrValue.end : nodeAttrName.end; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((quotelessValue == null) ? 0 : quotelessValue.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - DOMAttr other = (DOMAttr) obj; - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (quotelessValue == null) { - if (other.quotelessValue != null) { - return false; - } - } else if (!quotelessValue.equals(other.quotelessValue)) { - return false; - } - return true; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCDATASection.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCDATASection.java deleted file mode 100644 index c05d0b375..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCDATASection.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import org.w3c.dom.CDATASection; - -/** - * A CData section node. - * - */ -public class DOMCDATASection extends DOMText implements CDATASection { - - int startContent; - int endContent; - - public DOMCDATASection(int start, int end) { - super(start, end); - } - - @Override - public int getStartContent() { - return startContent; - } - - @Override - public int getEndContent() { - return endContent; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.w3c.dom.Text#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.CDATA_SECTION_NODE; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCharacterData.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCharacterData.java deleted file mode 100644 index 943c8cf08..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMCharacterData.java +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import static java.lang.System.lineSeparator; - -import java.util.List; - -import org.eclipse.lemminx.commons.BadLocationException; -import org.eclipse.lemminx.utils.StringUtils; -import org.w3c.dom.DOMException; - -/** - * A CharacterData node. - * - */ -public abstract class DOMCharacterData extends DOMNode implements org.w3c.dom.CharacterData { - - private String data; - - private String normalizedData; - - private boolean isWhitespace; - - private String delimiter; - - public DOMCharacterData(int start, int end) { - super(start, end); - } - - public boolean hasMultiLine() { - return getData().contains(getDelimiter()); - } - - public String getDelimiter() { - if (delimiter != null) { - return delimiter; - } - try { - delimiter = getOwnerDocument().getTextDocument().lineDelimiter(0); - return delimiter; - } catch (BadLocationException e) { - delimiter = lineSeparator(); - return delimiter; - } - } - - /** - * If data ends with a new line character. - * - * Returns false if a character is found before a new line. Non-newline - * whitespace will be ignored while searching. - * - * If no data exists, returns false. - * - * @return true if newline character ocurrs before non-whitespace character - */ - public boolean endsWithNewLine() { - if (hasData()) { - for (int i = data.length() - 1; i >= 0; i--) { - char c = data.charAt(i); - if (!Character.isWhitespace(c)) { - return false; - } - if (c == '\n') { - return true; - } - - } - } - return false; - } - - /** - * If data ends with a new line character. - * - * Returns false if a character is found before a new line. Non-newline - * whitespace will be ignored while searching. - * - * @return true if newline character ocurrs before non-whitespace character - */ - public boolean startsWithNewLine() { - if (hasData()) { - for (int i = 0; i < data.length(); i++) { - char c = data.charAt(i); - if (!Character.isWhitespace(c)) { - return false; - } - if (c == '\n' || c == '\r') { - return true; - } - - } - } - return false; - } - - public String getNormalizedData() { - if (normalizedData == null) { - normalizedData = StringUtils.normalizeSpace(getData()); - } - return normalizedData; - } - - public boolean hasData() { - return !getData().isEmpty(); - } - - /** - * Returns true if this node has sibling nodes. - */ - public boolean hasSiblings() { - List childrenOfParent = this.parent.getChildren(); - return childrenOfParent.size() > 1; - } - - public int getStartContent() { - return start; - } - - public int getEndContent() { - return end; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#getData() - */ - @Override - public String getData() { - if (data == null) { - data = getOwnerDocument().getText().substring(getStartContent(), getEndContent()); - } - return data; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeValue() - */ - @Override - public String getNodeValue() throws DOMException { - return getData(); - } - - /** - * @return the isWhitespace - */ - public boolean isWhitespace() { - return isWhitespace; - } - - /** - * Set true if this node's data is all whitespace - * - * @param isWhitespace - */ - public void setWhitespace(boolean isWhitespace) { - this.isWhitespace = isWhitespace; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#appendData(java.lang.String) - */ - @Override - public void appendData(String data) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#deleteData(int, int) - */ - @Override - public void deleteData(int offset, int count) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#getLength() - */ - @Override - public int getLength() { - return getData().length(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#insertData(int, java.lang.String) - */ - @Override - public void insertData(int offset, String data) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#replaceData(int, int, java.lang.String) - */ - @Override - public void replaceData(int offset, int count, String data) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#setData(java.lang.String) - */ - @Override - public void setData(String value) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.CharacterData#substringData(int, int) - */ - @Override - public String substringData(int offset, int count) throws DOMException { - throw new UnsupportedOperationException(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMComment.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMComment.java deleted file mode 100644 index f537d3942..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMComment.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -/** - * A Comment node. - * - */ -public class DOMComment extends DOMCharacterData implements org.w3c.dom.Comment { - - boolean commentSameLineEndTag; - - int startContent; - - int endContent; - - public DOMComment(int start, int end) { - super(start, end); - } - - public boolean isCommentSameLineEndTag() { - return commentSameLineEndTag; - } - - @Override - public int getStartContent() { - return startContent; - } - - @Override - public int getEndContent() { - return endContent; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.COMMENT_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return "#comment"; - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocument.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocument.java deleted file mode 100644 index 90667caaf..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocument.java +++ /dev/null @@ -1,947 +0,0 @@ -/** - * Copyright (c) 2018-2020 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.commons.BadLocationException; -import org.eclipse.lemminx.commons.TextDocument; -import org.eclipse.lemminx.dom.parser.Constants; -import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager; -import org.eclipse.lemminx.utils.DOMUtils; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lemminx.utils.XMLPositionUtility; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; -import org.w3c.dom.CDATASection; -import org.w3c.dom.DOMConfiguration; -import org.w3c.dom.DOMException; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.Document; -import org.w3c.dom.DocumentFragment; -import org.w3c.dom.EntityReference; -import org.w3c.dom.NodeList; - -/** - * XML document. - * - */ -public class DOMDocument extends DOMNode implements Document { - - private SchemaLocation schemaLocation; - private NoNamespaceSchemaLocation noNamespaceSchemaLocation; - private List xmlModels; - - private boolean referencedExternalGrammarInitialized; - private boolean referencedSchemaInitialized; - private final URIResolverExtensionManager resolverExtensionManager; - - private final TextDocument textDocument; - private boolean hasNamespaces; - private Map externalGrammarLocation; - private String schemaInstancePrefix; - private String schemaPrefix; - private CancelChecker cancelChecker; - private String externalGrammarFromNamespaceURI; - - public DOMDocument(TextDocument textDocument, URIResolverExtensionManager resolverExtensionManager) { - super(0, textDocument.getText().length()); - this.textDocument = textDocument; - this.resolverExtensionManager = resolverExtensionManager; - resetGrammar(); - } - - public void setCancelChecker(CancelChecker cancelChecker) { - this.cancelChecker = cancelChecker; - } - - public CancelChecker getCancelChecker() { - return cancelChecker; - } - - public List getRoots() { - return super.getChildren(); - } - - public Position positionAt(int offset) throws BadLocationException { - checkCanceled(); - return textDocument.positionAt(offset); - } - - public int offsetAt(Position position) throws BadLocationException { - checkCanceled(); - return textDocument.offsetAt(position); - } - - public String lineText(int lineNumber) throws BadLocationException { - checkCanceled(); - return textDocument.lineText(lineNumber); - } - - public String lineDelimiter(int lineNumber) throws BadLocationException { - checkCanceled(); - return textDocument.lineDelimiter(lineNumber); - } - - public LineIndentInfo getLineIndentInfo(int lineNumber) throws BadLocationException { - String lineText = lineText(lineNumber); - String lineDelimiter = lineDelimiter(lineNumber); - String whitespacesIndent = StringUtils.getStartWhitespaces(lineText); - return new LineIndentInfo(lineDelimiter, whitespacesIndent); - } - - /** - * Returns the element name on the left of the given position and null - * otherwise. - * - * @param textOffset - * @return the element name on the left of the given position and null - * otherwise. - */ - public Range getElementNameRangeAt(int textOffset) { - checkCanceled(); - return textDocument.getWordRangeAt(textOffset, Constants.ELEMENT_NAME_REGEX); - } - - @Override - public String getNamespaceURI() { - DOMElement documentElement = getDocumentElement(); - return documentElement != null ? documentElement.getNamespaceURI() : null; - } - - /** - * Returns the text content of the XML document. - * - * @return the text content of the XML document. - */ - public String getText() { - return textDocument.getText(); - } - - public TextDocument getTextDocument() { - return textDocument; - } - - /** - * Returns true if the document is bound to a grammar and false otherwise. - * - * @return true if the document is bound to a grammar and false otherwise. - */ - public boolean hasGrammar() { - return hasDTD() || hasSchemaLocation() || hasNoNamespaceSchemaLocation() || hasExternalGrammar() - || hasXMLModel(); - } - - // -------------------------- Grammar with XML Schema - - /** - * Returns the declared "xsi:schemaLocation" and null otherwise. - * - * @return the declared "xsi:schemaLocation" and null otherwise. - */ - public SchemaLocation getSchemaLocation() { - initializeReferencedSchemaIfNeeded(); - return schemaLocation; - } - - /** - * Returns true if XML root element declares a "xsi:schemaLocation" and false - * otherwise. - * - * @return true if XML root element declares a "xsi:schemaLocation" and false - * otherwise. - */ - public boolean hasSchemaLocation() { - return getSchemaLocation() != null; - } - - /** - * Returns the declared "xsi:noNamespaceSchemaLocation" and null otherwise. - * - * @return the declared "xsi:noNamespaceSchemaLocation" and null otherwise. - */ - public NoNamespaceSchemaLocation getNoNamespaceSchemaLocation() { - initializeReferencedSchemaIfNeeded(); - return noNamespaceSchemaLocation; - } - - /** - * Returns true if XML root element declares a "xsi:noNamespaceSchemaLocation" - * and false otherwise. - * - * @return true if XML root element declares a "xsi:noNamespaceSchemaLocation" - * and false otherwise. - */ - public boolean hasNoNamespaceSchemaLocation() { - return getNoNamespaceSchemaLocation() != null; - } - - /** - * Returns true if document defines namespaces (with xmlns) and false otherwise. - * - * @return true if document defines namespaces (with xmlns) and false otherwise. - */ - public boolean hasNamespaces() { - initializeReferencedSchemaIfNeeded(); - return hasNamespaces; - } - - /** - * Returns the (xsi) schema instance prefix and null otherwise. - * - * @return the (xsi) schema instance prefix and null otherwise. - */ - public String getSchemaInstancePrefix() { - initializeReferencedSchemaIfNeeded(); - return schemaInstancePrefix; - } - - /** - * Returns true if (xsi) schema instance prefix exists. - * - * @return true if (xsi) schema instance prefix exists. - */ - public boolean hasSchemaInstancePrefix() { - initializeReferencedSchemaIfNeeded(); - return schemaInstancePrefix != null; - } - - /** - * Initialize schemaLocation, noNamespaceSchemaLocation and hasNamespaces - * information if needed. - */ - private void initializeReferencedSchemaIfNeeded() { - if (referencedSchemaInitialized) { - return; - } - initializeReferencedSchema(); - referencedSchemaInitialized = true; - } - - /** - * Initialize namespaces and schema location declaration . - */ - private synchronized void initializeReferencedSchema() { - if (referencedSchemaInitialized) { - return; - } - // xml-model - xmlModels = XMLModel.createXMLModels(this); - // Get root element - DOMElement documentElement = getDocumentElement(); - if (documentElement == null) { - return; - } - schemaInstancePrefix = null; - schemaPrefix = null; - // Search if document element root declares namespace with "xmlns". - if (documentElement.hasAttributes()) { - for (DOMAttr attr : documentElement.getAttributeNodes()) { - String attributeName = attr.getName(); - if (attributeName != null) { - if (attributeName.equals(DOMAttr.XMLNS_ATTR) - || attributeName.startsWith(DOMAttr.XMLNS_NO_DEFAULT_ATTR)) { - hasNamespaces = true; - String attributeValue = documentElement.getAttribute(attributeName); - if (attributeValue != null && attributeValue.startsWith("http://www.w3.org/")) { - if (attributeValue.endsWith("/XMLSchema-instance")) { - schemaInstancePrefix = attributeName.equals("xmlns") ? "" - : getUnprefixedName(attributeName); - } else if (attributeValue.endsWith("/XMLSchema")) { - schemaPrefix = attributeName.equals("xmlns") ? "" : getUnprefixedName(attributeName); - } - } - } - } - } - if (schemaInstancePrefix != null) { - // DOM document can declared xsi:noNamespaceSchemaLocation and - // xsi:schemaLocation both even it's not valid - noNamespaceSchemaLocation = createNoNamespaceSchemaLocation(documentElement, schemaInstancePrefix); - schemaLocation = createSchemaLocation(documentElement, schemaInstancePrefix); - } - } - } - - /** - * If document has {@code } - * - * @return - */ - public boolean hasProlog() { - List children = getChildren(); - return (children != null && !children.isEmpty() && children.get(0).isProlog()); - } - - /** - * If document has {@code }, return this prolog, null otherwise - * - * @return prolog DOMNode, if the document has one, null otherwise - */ - public DOMNode getProlog() { - if (hasProlog()) { - return getChild(0); - } else { - return null; - } - } - - /** - * Returns true, if the given offset is before XML declaration - * ({@code }), false otherwise. - * - * @param offset the offset position in question - * @return true, if before xml declaration; false otherwise - */ - public boolean isBeforeProlog(int offset) { - return hasProlog() && offset <= getProlog().getStart(); - } - - private static SchemaLocation createSchemaLocation(DOMNode root, String schemaInstancePrefix) { - DOMAttr attr = root.getAttributeNode(getPrefixedName(schemaInstancePrefix, "schemaLocation")); - if (attr == null) { - return null; - } - return new SchemaLocation(attr); - } - - private static NoNamespaceSchemaLocation createNoNamespaceSchemaLocation(DOMNode root, - String schemaInstancePrefix) { - DOMAttr attr = root.getAttributeNode(getPrefixedName(schemaInstancePrefix, "noNamespaceSchemaLocation")); - if (attr == null || attr.getValue() == null) { - return null; - } - return new NoNamespaceSchemaLocation(attr); - } - - // -------------------------- Grammar with DTD - - /** - * Returns true if XML document has a DTD declaration and false otherwise. - * - * @return true if XML document has a DTD declaration and false otherwise. - */ - public boolean hasDTD() { - return getDoctype() != null; - } - - // -------------------------- Grammar with getXMLModels() { - initializeReferencedSchemaIfNeeded(); - return xmlModels; - } - - // -------------------------- External Grammar (XML file associations, catalog) - - /** - * Returns true if the document is bound to an external grammar (XML file - * associations, XLM catalog) and false otherwise. - * - * @return true if the document is bound to an external grammar (XML file - * associations, XLM catalog) and false otherwise. - */ - public boolean hasExternalGrammar() { - return getExternalGrammarLocation() != null || getExternalGrammarFromNamespaceURI() != null; - } - - /** - * Returns the external grammar location (XSD, DTD from xml file associations) - * and null otherwise. - * - * @return the external grammar location (XSD, DTD from xml file associations) - * and null otherwise. - */ - public Map getExternalGrammarLocation() { - initializeReferencedExternalGrammarIfNeeded(); - return externalGrammarLocation; - } - - /** - * Returns the grammar location found by the namespace URI from the document - * root element (ex : found with XML catalog) and null otherwise. - * - * @return the grammar location found by the namespace URI from the document - * root element (ex : found with XML catalog) and null otherwise. - */ - public String getExternalGrammarFromNamespaceURI() { - initializeReferencedExternalGrammarIfNeeded(); - return externalGrammarFromNamespaceURI; - } - - private void initializeReferencedExternalGrammarIfNeeded() { - if (referencedExternalGrammarInitialized) { - return; - } - intializeExternalGrammar(); - } - - private synchronized void intializeExternalGrammar() { - if (referencedExternalGrammarInitialized) { - return; - } - try { - if (resolverExtensionManager != null) { - // No grammar found with standard mean, check if it some components like XML - // file associations bind this XML document to a grammar with external schema - // location. - try { - externalGrammarLocation = resolverExtensionManager - .getExternalGrammarLocation(new URI(getDocumentURI())); - if (externalGrammarLocation != null) { - return; - } - } catch (URISyntaxException e) { - // Do nothing - } - - // No grammar found with standard mean and external schema location, check if - // it some components like XML - // Catalog, XSL and XSD resolvers, etc bind this XML document to a grammar. - // Get root element - DOMElement documentElement = getDocumentElement(); - if (documentElement == null) { - return; - } - String namespaceURI = documentElement.getNamespaceURI(); - externalGrammarFromNamespaceURI = resolverExtensionManager.resolve(getDocumentURI(), namespaceURI, - null); - } - } finally { - referencedExternalGrammarInitialized = true; - } - } - - private static String getUnprefixedName(String name) { - int index = name.indexOf(":"); //$NON-NLS-1$ - if (index != -1) { - name = name.substring(index + 1); - } - return name; - } - - private static String getPrefixedName(String prefix, String localName) { - return prefix != null && prefix.length() > 0 ? prefix + ":" + localName : localName; //$NON-NLS-1$ - } - - public DOMElement createElement(int start, int end) { - return new DOMElement(start, end); - } - - public DOMCDATASection createCDataSection(int start, int end) { - return new DOMCDATASection(start, end); - } - - public DOMProcessingInstruction createProcessingInstruction(int start, int end) { - return new DOMProcessingInstruction(start, end); - } - - public DOMComment createComment(int start, int end) { - return new DOMComment(start, end); - } - - public DOMText createText(int start, int end) { - return new DOMText(start, end); - } - - public DOMDocumentType createDocumentType(int start, int end) { - return new DOMDocumentType(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.DOCUMENT_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return "#document"; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getDocumentElement() - */ - @Override - public DOMElement getDocumentElement() { - List roots = getRoots(); - if (roots != null) { - for (DOMNode node : roots) { - if (node.isElement()) { - return (DOMElement) node; - } - } - } - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getDoctype() - */ - @Override - public DOMDocumentType getDoctype() { - List roots = getRoots(); - if (roots != null) { - for (DOMNode node : roots) { - if (node.isDoctype()) { - return (DOMDocumentType) node; - } - } - } - return null; - } - - @Override - public DOMDocument getOwnerDocument() { - return this; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getDocumentURI() - */ - @Override - public String getDocumentURI() { - return textDocument.getUri(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#setDocumentURI(java.lang.String) - */ - @Override - public void setDocumentURI(String documentURI) { - textDocument.setUri(documentURI); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#adoptNode(org.w3c.dom.Node) - */ - @Override - public DOMNode adoptNode(org.w3c.dom.Node source) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createAttribute(java.lang.String) - */ - @Override - public DOMAttr createAttribute(String name) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createAttributeNS(java.lang.String, - * java.lang.String) - */ - @Override - public DOMAttr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createCDATASection(java.lang.String) - */ - @Override - public CDATASection createCDATASection(String data) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createComment(java.lang.String) - */ - @Override - public DOMComment createComment(String data) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createDocumentFragment() - */ - @Override - public DocumentFragment createDocumentFragment() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createElement(java.lang.String) - */ - @Override - public DOMElement createElement(String tagName) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createElementNS(java.lang.String, java.lang.String) - */ - @Override - public DOMElement createElementNS(String namespaceURI, String qualifiedName) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createEntityReference(java.lang.String) - */ - @Override - public EntityReference createEntityReference(String name) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createProcessingInstruction(java.lang.String, - * java.lang.String) - */ - @Override - public DOMProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#createTextNode(java.lang.String) - */ - @Override - public DOMText createTextNode(String data) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getDomConfig() - */ - @Override - public DOMConfiguration getDomConfig() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getElementById(java.lang.String) - */ - @Override - public DOMElement getElementById(String elementId) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getElementsByTagName(java.lang.String) - */ - @Override - public NodeList getElementsByTagName(String tagname) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getElementsByTagNameNS(java.lang.String, - * java.lang.String) - */ - @Override - public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getImplementation() - */ - @Override - public DOMImplementation getImplementation() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getInputEncoding() - */ - @Override - public String getInputEncoding() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getStrictErrorChecking() - */ - @Override - public boolean getStrictErrorChecking() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getXmlEncoding() - */ - @Override - public String getXmlEncoding() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getXmlStandalone() - */ - @Override - public boolean getXmlStandalone() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#getXmlVersion() - */ - @Override - public String getXmlVersion() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) - */ - @Override - public DOMNode importNode(org.w3c.dom.Node importedNode, boolean deep) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#normalizeDocument() - */ - @Override - public void normalizeDocument() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#renameNode(org.w3c.dom.Node, java.lang.String, - * java.lang.String) - */ - @Override - public DOMNode renameNode(org.w3c.dom.Node n, String namespaceURI, String qualifiedName) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#setStrictErrorChecking(boolean) - */ - @Override - public void setStrictErrorChecking(boolean strictErrorChecking) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#setXmlStandalone(boolean) - */ - @Override - public void setXmlStandalone(boolean xmlStandalone) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Document#setXmlVersion(java.lang.String) - */ - @Override - public void setXmlVersion(String xmlVersion) throws DOMException { - throw new UnsupportedOperationException(); - } - - /** - * Reset the cached grammar flag. - */ - public void resetGrammar() { - this.referencedExternalGrammarInitialized = false; - this.referencedSchemaInitialized = false; - } - - public URIResolverExtensionManager getResolverExtensionManager() { - return resolverExtensionManager; - } - - /** - * Returns true if the XML document is a DTD and false otherwise. - * - * @return true if the XML document is a DTD and false otherwise. - */ - public boolean isDTD() { - String uri = this.getDocumentURI(); - if (DOMUtils.isDTD(uri)) { - return true; - } - return false; - } - - /** - * Returns true if 'offset' is within an internal DOCTYPE dtd. Else false. - * - * @param offset - * @return - */ - public boolean isWithinInternalDTD(int offset) { - DOMDocumentType doctype = this.getDoctype(); - if (doctype != null && doctype.internalSubset != null) { - return offset > doctype.internalSubset.start && offset < doctype.internalSubset.end; - } - return false; - } - - public Range getTrimmedRange(Range range) { - if (range != null) { - return getTrimmedRange(range.getStart().getCharacter(), range.getEnd().getCharacter()); - } - return null; - - } - - public Range getTrimmedRange(int start, int end) { - String text = getText(); - char c = text.charAt(start); - while (Character.isWhitespace(c)) { - start++; - c = text.charAt(start); - } - if (start == end) { - return null; - } - end--; - c = text.charAt(end); - while (Character.isWhitespace(c)) { - end--; - c = text.charAt(end); - } - end++; - return XMLPositionUtility.createRange(start, end, this); - } - - /** - * Returns the DTD Attribute list for the given element name and empty - * otherwise. - * - * @param elementName - * @return the DTD Attribute list for the given element name and empty - * otherwise. - */ - public Collection findDTDAttrList(String elementName) { - DOMDocumentType docType = getDoctype(); - if (docType == null || elementName == null) { - return Collections.emptyList(); - } - return docType.getChildren().stream().filter(DOMNode::isDTDAttListDecl) - .filter(n -> elementName.equals(((DTDAttlistDecl) n).getElementName())).collect(Collectors.toList()); - } - - /** - * Returns the XML Schema prefix (ex : 'xs' for - * xmlns:xs="http://www.w3.org/2001/XMLSchema") - * - * @return the XML Schema prefix (ex : 'xs' for - * xmlns:xs="http://www.w3.org/2001/XMLSchema") - */ - public String getSchemaPrefix() { - initializeReferencedSchemaIfNeeded(); - return schemaPrefix; - } - - private void checkCanceled() { - if (cancelChecker != null) { - cancelChecker.checkCanceled(); - } - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocumentType.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocumentType.java deleted file mode 100644 index 25e0bf33c..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMDocumentType.java +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Copyright (c) 2018-2020 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import java.util.List; - -import org.w3c.dom.NamedNodeMap; - -/** - * A doctype node. - * - */ -public class DOMDocumentType extends DTDDeclNode implements org.w3c.dom.DocumentType { - - public static enum DocumentTypeKind { - PUBLIC, SYSTEM, INVALID - } - - private XMLNamedNodeMap entitiesNodes; - - DTDDeclParameter kind; // SYSTEM || PUBLIC - DTDDeclParameter publicId; - DTDDeclParameter systemId; - DTDDeclParameter internalSubset; - - private String content; // || - - public DOMDocumentType(int start, int end) { - super(start, end); - } - - @Override - public DOMDocumentType getOwnerDocType() { - return this; - } - - @Override - public String getTextContent() { - if (content == null) { - content = getOwnerDocument().getText().substring(getStart(), getEnd()); - } - return content; - } - - /** - * Returns the document type kind (PUBLIC or SYSTEM) - * - * @return the document type kind (PUBLIC or SYSTEM) - */ - public String getKind() { - return kind != null ? kind.getParameter() : null; - } - - /** - * Returns the node where document type kind (PUBLIC or SYSTEM) is declared - * - * @return the node where document type kind (PUBLIC or SYSTEM) is declared - */ - public DTDDeclParameter getKindNode() { - return kind; - } - - /** - * @param kind the DocumentTypeKind to set - */ - void setKind(int start, int end) { - kind = addNewParameter(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return getName(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.DOCUMENT_TYPE_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.DocumentType#getEntities() - */ - @Override - public NamedNodeMap getEntities() { - if (entitiesNodes == null) { - entitiesNodes = new XMLNamedNodeMap<>(); - List children = super.getChildren(); - for (DOMNode child : children) { - if (child.getNodeType() == DOMNode.ENTITY_NODE) { - entitiesNodes.add((DTDEntityDecl) child); - } - } - } - return entitiesNodes; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.DocumentType#getInternalSubset() - */ - @Override - public String getInternalSubset() { - if (internalSubset != null) { - // Returns subset without '[' and ']' - return internalSubset.getParameterWithoutFirstAndLastChar(); - } - return null; - } - - public void setStartInternalSubset(int start) { - internalSubset = addNewParameter(start, start + 1); - } - - public void setEndInternalSubset(int end) { - updateLastParameterEnd(end); - } - - public boolean isInternalSubset(DTDDeclParameter parameter) { - if (this.internalSubset != null) { - return this.internalSubset.equals(parameter); - } - return false; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.DocumentType#getNotations() - */ - @Override - public NamedNodeMap getNotations() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.DocumentType#getPublicId() - */ - @Override - public String getPublicId() { - return publicId != null ? publicId.getParameter() : null; - } - - public String getPublicIdWithoutQuotes() { - return publicId != null ? publicId.getParameterWithoutFirstAndLastChar() : null; - } - - public DTDDeclParameter getPublicIdNode() { - return publicId; - } - - /** - * @param publicId the publicId to set - */ - void setPublicId(int start, int end) { - publicId = addNewParameter(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.DocumentType#getSystemId() - */ - @Override - public String getSystemId() { - return systemId != null ? systemId.getParameter() : null; - } - - public DTDDeclParameter getSystemIdNode() { - return systemId; - } - - public String getSystemIdWithoutQuotes() { - return systemId != null ? systemId.getParameterWithoutFirstAndLastChar() : null; - } - - /** - * @param systemId the systemId to set - */ - void setSystemId(int start, int end) { - systemId = addNewParameter(start, end); - } - - /** - * Returns a substring of the whole document. - * - * - * Since offset values are relative to 'this.start' we need to subtract - * getStart() to make them relative to 'content' - */ - public String getSubstring(int start, int end) { - String textContent = getTextContent(); - if (textContent == null) { - return null; - } - return textContent.substring(start - getStart(), end - getStart()); - } - - /** - * Returns the declaration parameter that represents the internal subset, or null if there is no internal subset - * - * @return the declaration parameter that represents the internal subset, or null if there is no internal subset - */ - public DTDDeclParameter getInternalSubsetNode() { - return this.internalSubset; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMElement.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMElement.java deleted file mode 100644 index c39228ba4..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMElement.java +++ /dev/null @@ -1,567 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import static org.eclipse.lemminx.dom.DOMAttr.XMLNS_ATTR; -import static org.eclipse.lemminx.dom.DOMAttr.XMLNS_NO_DEFAULT_ATTR; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import org.eclipse.lemminx.utils.StringUtils; -import org.w3c.dom.DOMException; -import org.w3c.dom.NodeList; -import org.w3c.dom.TypeInfo; - -/** - * An Element node. - * - */ -public class DOMElement extends DOMNode implements org.w3c.dom.Element { - - String tag; - boolean selfClosed; - - // DomElement.start == startTagOpenOffset - int startTagOpenOffset = NULL_VALUE; // | - int startTagCloseOffset = NULL_VALUE; // - - int endTagOpenOffset = NULL_VALUE; // | - int endTagCloseOffset = NULL_VALUE;// - // DomElement.end = | , is always scanner.getTokenEnd() - - public DOMElement(int start, int end) { - super(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.ELEMENT_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return getTagName(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Element#getTagName() - */ - @Override - public String getTagName() { - return tag; - } - - /** - * Returns true if the DOM element have a tag name and false otherwise (ex : '<' - * or ' getAllPrefixes() { - if (hasAttributes()) { - Collection prefixes = new ArrayList<>(); - for (DOMAttr attr : getAttributeNodes()) { - if (attr.isNoDefaultXmlns()) { - prefixes.add(attr.extractPrefixFromXmlns()); - } - } - return prefixes; - } - return Collections.emptyList(); - } - - /** - * Returns the xmlns prefix from the given namespace URI and null otherwise. - * - * @param namespaceURI the namespace - * @return the xmlns prefix from the given namespace URI and null otherwise. - */ - public String getPrefix(String namespaceURI) { - if (namespaceURI == null) { - return null; - } - if (hasAttributes()) { - for (DOMAttr attr : getAttributeNodes()) { - String prefix = attr.getPrefixIfMatchesURI(namespaceURI); - if (prefix != null) { - return prefix; - } - } - } - // try to get the prefix in the parent element - DOMNode parent = getParentNode(); - while (parent != null) { - if (parent.getNodeType() == DOMNode.ELEMENT_NODE) { - DOMElement parentElement = ((DOMElement) parent); - String prefix = parentElement.getPrefix(namespaceURI); - if (prefix != null) { - return prefix; - } - } - parent = parent.getParentNode(); - } - return null; - } - - public boolean isDocumentElement() { - return this.equals(getOwnerDocument().getDocumentElement()); - } - - public boolean isSelfClosed() { - return selfClosed; - } - - /** - * Will traverse backwards from the start offset returning an offset of the - * given character if it's found before another character. Whitespace is - * ignored. - * - * Returns null if the character is not found. - * - * The initial value for the start offset is not included. So have the offset 1 - * position after the character you want to start at. - */ - public Integer endsWith(char c, int startOffset) { - String text = this.getOwnerDocument().getText(); - if (startOffset > text.length() || startOffset < 0) { - return null; - } - startOffset--; - while (startOffset >= 0) { - char current = text.charAt(startOffset); - if (Character.isWhitespace(current)) { - startOffset--; - continue; - } - if (current != c) { - return null; - } - return startOffset; - } - return null; - } - - /** - * Returns true if the given tag is the same tag of this element and false - * otherwise. - * - * @param tag tag element - * @return true if the given tag is the same tag of this element and false - * otherwise. - */ - public boolean isSameTag(String tag) { - return Objects.equals(this.tag, tag); - } - - public boolean isInStartTag(int offset) { - if (startTagOpenOffset == NULL_VALUE || startTagCloseOffset == NULL_VALUE) { - // case <| - return true; - } - if (offset > startTagOpenOffset && offset <= startTagCloseOffset) { - // case - return true; - } - return false; - } - - public boolean isInEndTag(int offset) { - return isInEndTag(offset, false); - } - - public boolean isInEndTag(int offset, boolean afterBackSlash) { - if (endTagOpenOffset == NULL_VALUE) { - // case >| - return false; - } - if (offset > endTagOpenOffset + (afterBackSlash ? 1 : 0) && offset < getEnd()) { - // case - return true; - } - return false; - } - - public boolean isInInsideStartEndTag(int offset) { - return offset > startTagCloseOffset && offset <= endTagOpenOffset; - } - - /** - * Returns the start tag open offset and {@link DOMNode#NULL_VALUE} if it - * doesn't exist. - * - * @return the start tag open offset and {@link DOMNode#NULL_VALUE} if it - * doesn't exist. - */ - public int getStartTagOpenOffset() { - return startTagOpenOffset; - } - - /** - * Returns the start tag close offset and {@link DOMNode#NULL_VALUE} if it - * doesn't exist. - * - * @return the start tag close offset and {@link DOMNode#NULL_VALUE} if it - * doesn't exist. - */ - public int getStartTagCloseOffset() { - return startTagCloseOffset; - } - - /** - * Returns the end tag open offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - * - * @return the end tag open offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - */ - public int getEndTagOpenOffset() { - return endTagOpenOffset; - } - - /** - * Returns the end tag close offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - * - * @return the end tag close offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - */ - public int getEndTagCloseOffset() { - return endTagCloseOffset; - } - - /** - * Returns true if has a start tag. - * - * In our source-oriented DOM, a lone end tag will cause a node to be created in - * the tree, unlike well-formed-only DOMs. - * - * @return true if has a start tag. - */ - public boolean hasStartTag() { - return getStartTagOpenOffset() != NULL_VALUE; - } - - /** - * Returns true if has an end tag. - * - * In our source-oriented DOM, sometimes Elements are "ended", even without an - * explicit end tag in the source. - * - * @return true if has an end tag. - */ - public boolean hasEndTag() { - return getEndTagOpenOffset() != NULL_VALUE; - } - - /** - * If '>' exists in - */ - public boolean isStartTagClosed() { - return getStartTagCloseOffset() != NULL_VALUE; - } - - /** - * If '>' exists in - */ - public boolean isEndTagClosed() { - return getEndTagCloseOffset() != NULL_VALUE; - } - - /** - * Returns true if the given element is an orphan end tag (which has no start - * tag, eg: ) and false otherwise. - * - * @return true if the given element is an orphan end tag (which has no start - * tag, eg: ) and false otherwise. - */ - public boolean isOrphanEndTag() { - return hasEndTag() && !hasStartTag(); - } - - /** - * Returns true if the given element is an orphan end tag (which has no start - * tag, eg: ) of the given tag name and false otherwise. - * - * @param tagName the end tag name. - * @return true if the given element is an orphan end tag (which has no start - * tag, eg: ) of the given tag name and false otherwise. - */ - public boolean isOrphanEndTagOf(String tagName) { - return isSameTag(tagName) && isOrphanEndTag(); - } - - /** - * Returns the offset at which the given unclosed start tag should be closed with an angle bracket - * - * @returns the offset at which the given unclosed start tag should be closed with an angle bracket - */ - public int getUnclosedStartTagCloseOffset() { - String documentText = getOwnerDocument().getText(); - int i = getStart() + 1; - for (; i < documentText.length() && documentText.charAt(i) != '/' && documentText.charAt(i) != '<'; i++) { - } - if (i < documentText.length() && documentText.charAt(i) == '/') { - return i + 1; - } - i--; - for (; i > 0 && Character.isWhitespace(documentText.charAt(i)); i--) { - } - return i + 1; - } - - @Override - public DOMElement getOrphanEndElement(int offset, String tagName) { - if (getEnd() <= offset) { - // | - // | - // | - // check if next sibling node is an element like <\tagName> - return super.getOrphanEndElement(offset, tagName); - } - if (isSameTag(tagName) && isInStartTag(offset)) { - // - return hasEndTag() ? this : null; - } - // search if it exists an end tag - List children = getChildren(); - for (DOMNode child : children) { - if (child.isElement()) { - DOMElement childElement = (DOMElement) child; - if (childElement.isOrphanEndTagOf(tagName)) { - return childElement; - } - } - } - return null; - } - - /** - * Returns true if element has a closing end tag (eg: ) and false - * otherwise (eg: ). - * - * @return true if element has a closing end tag (eg: ) and false - * otherwise (eg: ). - */ - @Override - public boolean isClosed() { - return super.isClosed(); - } - - @Override - public String getAttributeNS(String arg0, String arg1) throws DOMException { - return null; - } - - @Override - public DOMAttr getAttributeNode(String name) { - return super.getAttributeNode(name); - } - - @Override - public DOMAttr getAttributeNodeNS(String arg0, String arg1) throws DOMException { - return null; - } - - @Override - public NodeList getElementsByTagName(String arg0) { - return null; - } - - @Override - public NodeList getElementsByTagNameNS(String arg0, String arg1) throws DOMException { - return null; - } - - @Override - public TypeInfo getSchemaTypeInfo() { - return null; - } - - @Override - public boolean hasAttributeNS(String arg0, String arg1) throws DOMException { - return false; - } - - @Override - public void removeAttribute(String arg0) throws DOMException { - } - - @Override - public void removeAttributeNS(String arg0, String arg1) throws DOMException { - } - - @Override - public DOMAttr removeAttributeNode(org.w3c.dom.Attr arg0) throws DOMException { - return null; - } - - @Override - public void setAttributeNS(String arg0, String arg1, String arg2) throws DOMException { - } - - @Override - public DOMAttr setAttributeNode(org.w3c.dom.Attr arg0) throws DOMException { - return null; - } - - @Override - public DOMAttr setAttributeNodeNS(org.w3c.dom.Attr arg0) throws DOMException { - return null; - } - - @Override - public void setIdAttribute(String arg0, boolean arg1) throws DOMException { - } - - @Override - public void setIdAttributeNS(String arg0, String arg1, boolean arg2) throws DOMException { - } - - @Override - public void setIdAttributeNode(org.w3c.dom.Attr arg0, boolean arg1) throws DOMException { - } - - /** - * Returns true if the element is empty and false otherwise. - * - * @return true if the element is empty and false otherwise. - */ - public boolean isEmpty() { - if (!hasChildNodes()) { - return true; - } - for (DOMNode child : getChildren()) { - if (child.isText()) { - DOMText text = (DOMText) child; - if (!text.isWhitespace()) { - return false; - } - } else { - return false; - } - } - return true; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMNode.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMNode.java deleted file mode 100644 index 9daab6d1f..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMNode.java +++ /dev/null @@ -1,846 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; - -import org.w3c.dom.DOMException; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.UserDataHandler; - -/** - * DOM node. - * - */ -public abstract class DOMNode implements Node, DOMRange { - - /** - * Null value used for offset. - */ - public static final int NULL_VALUE = -1; - - /** - * The node is a DTD Element Declaration. - */ - public static final short DTD_ELEMENT_DECL_NODE = 101; - - /** - * The node is a DTD Attribute List. - */ - public static final short DTD_ATT_LIST_NODE = 102; - - /** - * The node is a DTD Entity Declaraction. - */ - public static final short DTD_ENTITY_DECL_NODE = 103; - - /** - * The node is a DTD Notation Declaraction. - */ - public static final short DTD_NOTATION_DECL = 104; - - /** - * The node is a generic DTD Decl Node. - */ - public static final short DTD_DECL_NODE = 105; - - boolean closed = false; - - private XMLNamedNodeMap attributeNodes; - private XMLNodeList children; - - final int start; // | - int end; // | - - DOMNode parent; - - private static final NodeList EMPTY_CHILDREN = new NodeList() { - - @Override - public Node item(int index) { - return null; - } - - @Override - public int getLength() { - return 0; - } - }; - - static class XMLNodeList extends ArrayList implements NodeList { - - private static final long serialVersionUID = 1L; - - @Override - public int getLength() { - return super.size(); - } - - @Override - public DOMNode item(int index) { - return super.get(index); - } - - } - - static class XMLNamedNodeMap extends ArrayList implements NamedNodeMap { - - private static final long serialVersionUID = 1L; - - @Override - public int getLength() { - return super.size(); - } - - @Override - public T getNamedItem(String name) { - for (T node : this) { - if (name.equals(node.getNodeName())) { - return node; - } - } - return null; - } - - @Override - public T getNamedItemNS(String name, String arg1) throws DOMException { - throw new UnsupportedOperationException(); - } - - @Override - public T item(int index) { - return super.get(index); - } - - @Override - public T removeNamedItem(String arg0) throws DOMException { - throw new UnsupportedOperationException(); - } - - @Override - public T removeNamedItemNS(String arg0, String arg1) throws DOMException { - throw new UnsupportedOperationException(); - } - - @Override - public T setNamedItem(org.w3c.dom.Node arg0) throws DOMException { - throw new UnsupportedOperationException(); - } - - @Override - public T setNamedItemNS(org.w3c.dom.Node arg0) throws DOMException { - throw new UnsupportedOperationException(); - } - - } - - public DOMNode(int start, int end) { - this.start = start; - this.end = end; - this.closed = false; - } - - /** - * Returns the owner document and null otherwise. - * - * @return the owner document and null otherwise. - */ - @Override - public DOMDocument getOwnerDocument() { - Node node = parent; - while (node != null) { - if (node.getNodeType() == Node.DOCUMENT_NODE) { - return (DOMDocument) node; - } - node = node.getParentNode(); - } - return null; - } - - @Override - public String toString() { - return toString(0); - } - - private String toString(int indent) { - StringBuilder result = new StringBuilder(""); - for (int i = 0; i < indent; i++) { - result.append("\t"); - } - result.append("{start: "); - result.append(start); - result.append(", end: "); - result.append(end); - result.append(", name: "); - result.append(getNodeName()); - result.append(", closed: "); - result.append(closed); - if (children != null && children.size() > 0) { - result.append(", \n"); - for (int i = 0; i < indent + 1; i++) { - result.append("\t"); - } - result.append("children:["); - for (int i = 0; i < children.size(); i++) { - DOMNode node = children.get(i); - result.append("\n"); - result.append(node.toString(indent + 2)); - if (i < children.size() - 1) { - result.append(","); - } - } - result.append("\n"); - for (int i = 0; i < indent + 1; i++) { - result.append("\t"); - } - result.append("]"); - result.append("\n"); - for (int i = 0; i < indent; i++) { - result.append("\t"); - } - result.append("}"); - } else { - result.append("}"); - } - return result.toString(); - } - - /** - * Returns the node before - */ - public DOMNode findNodeBefore(int offset) { - List children = getChildren(); - int idx = findFirst(children, c -> offset <= c.start) - 1; - if (idx >= 0) { - DOMNode child = children.get(idx); - if (offset > child.start) { - if (offset < child.end) { - return child.findNodeBefore(offset); - } - DOMNode lastChild = child.getLastChild(); - if (lastChild != null && lastChild.end == child.end) { - return child.findNodeBefore(offset); - } - return child; - } - } - return this; - } - - public DOMNode findNodeAt(int offset) { - List children = getChildren(); - int idx = findFirst(children, c -> offset <= c.start) - 1; - if (idx >= 0) { - DOMNode child = children.get(idx); - if (isIncluded(child, offset)) { - return child.findNodeAt(offset); - } - } - return this; - } - - /** - * Returns true if the node included the given offset and false otherwise. - * - * @param node - * @param offset - * @return true if the node included the given offset and false otherwise. - */ - public static boolean isIncluded(DOMRange node, int offset) { - if (node == null) { - return false; - } - return isIncluded(node.getStart(), node.getEnd(), offset); - } - - public static boolean isIncluded(int start, int end, int offset) { - return offset >= start && offset <= end; - } - - public DOMAttr findAttrAt(int offset) { - DOMNode node = findNodeAt(offset); - return findAttrAt(node, offset); - } - - public static DOMAttr findAttrAt(DOMNode node, int offset) { - if (node != null && node.hasAttributes()) { - for (DOMAttr attr : node.getAttributeNodes()) { - if (attr.isIncluded(offset)) { - return attr; - } - } - } - return null; - } - - public static DOMNode findNodeOrAttrAt(DOMDocument document, int offset) { - DOMNode node = document.findNodeAt(offset); - if (node != null) { - DOMAttr attr = findAttrAt(node, offset); - if (attr != null) { - return attr; - } - } - return node; - } - - /** - * Takes a sorted array and a function p. The array is sorted in such a way that - * all elements where p(x) is false are located before all elements where p(x) - * is true. - * - * @returns the least x for which p(x) is true or array.length if no element - * full fills the given function. - */ - private static int findFirst(List array, Function p) { - int low = 0, high = array.size(); - if (high == 0) { - return 0; // no children - } - while (low < high) { - int mid = (int) Math.floor((low + high) / 2); - if (p.apply(array.get(mid))) { - high = mid; - } else { - low = mid + 1; - } - } - return low; - } - - public DOMAttr getAttributeNode(String name) { - return getAttributeNode(null, name); - } - - /** - * Returns the attribute that matches the given name. - * - * If there is no namespace, set prefix to null. - */ - public DOMAttr getAttributeNode(String prefix, String suffix) { - StringBuilder sb = new StringBuilder(); - if (prefix != null) { - sb.append(prefix); - sb.append(":"); - } - sb.append(suffix); - String name = sb.toString(); - if (!hasAttributes()) { - return null; - } - for (DOMAttr attr : attributeNodes) { - if (name.equals(attr.getName())) { - return attr; - } - } - return null; - } - - public String getAttribute(String name) { - DOMAttr attr = getAttributeNode(name); - String value = attr != null ? attr.getValue() : null; - if (value == null) { - return null; - } - if (value.isEmpty()) { - return value; - } - // remove quote - char c = value.charAt(0); - if (c == '"' || c == '\'') { - if (value.charAt(value.length() - 1) == c) { - return value.substring(1, value.length() - 1); - } - return value.substring(1, value.length()); - } - return value; - } - - /** - * Returns the attribute at the given index, the order is how the attributes - * appear in the document. - * - * @param index Starting at 0, index of attribute you want - * @return - */ - public DOMAttr getAttributeAtIndex(int index) { - if (!hasAttributes()) { - return null; - } - - if (index > attributeNodes.getLength() - 1) { - return null; - } - return attributeNodes.get(index); - } - - public boolean hasAttribute(String name) { - return hasAttributes() && getAttributeNode(name) != null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#hasAttributes() - */ - @Override - public boolean hasAttributes() { - return attributeNodes != null && attributeNodes.size() != 0; - } - - public void setAttribute(String name, String value) { - DOMAttr attr = getAttributeNode(name); - if (attr == null) { - attr = new DOMAttr(name, this); - setAttributeNode(attr); - } - attr.setValue(value, -1, -1); - } - - public void setAttributeNode(DOMAttr attr) { - if (attributeNodes == null) { - attributeNodes = new XMLNamedNodeMap<>(); - } - attributeNodes.add(attr); - } - - public List getAttributeNodes() { - return attributeNodes; - } - - /** - * Returns a list of children, each having an attribute called name, with a - * value of value - * - * @param name name of attribute - * @param value value of attribute - * @return list of children, each having a specified attribute name and value - */ - public List getChildrenWithAttributeValue(String name, String value) { - List result = new ArrayList<>(); - for (DOMNode child : getChildren()) { - if (child.hasAttribute(name)) { - String attrValue = child.getAttribute(name); - if (Objects.equals(attrValue, value)) { - result.add(child); - } - } - } - return result; - } - - /** - * Returns the node children. - * - * @return the node children. - */ - public List getChildren() { - if (children == null) { - return Collections.emptyList(); - } - return children; - } - - /** - * Add node child and set child.parent to {@code this} - * - * @param child the node child to add. - */ - public void addChild(DOMNode child) { - child.parent = this; - if (children == null) { - children = new XMLNodeList<>(); - } - getChildren().add(child); - } - - /** - * Returns node child at the given index. - * - * @param index - * @return node child at the given index. - */ - public DOMNode getChild(int index) { - return getChildren().get(index); - } - - public boolean isClosed() { - return closed; - } - - public DOMElement getParentElement() { - DOMNode parent = getParentNode(); - DOMDocument ownerDocument = getOwnerDocument(); - while (parent != null && parent != ownerDocument) { - if (parent.isElement()) { - return (DOMElement) parent; - } - parent = parent.getParentNode(); - } - return null; - } - - public boolean isComment() { - return getNodeType() == DOMNode.COMMENT_NODE; - } - - public boolean isProcessingInstruction() { - return (getNodeType() == DOMNode.PROCESSING_INSTRUCTION_NODE) - && ((DOMProcessingInstruction) this).isProcessingInstruction(); - } - - public boolean isProlog() { - return (getNodeType() == DOMNode.PROCESSING_INSTRUCTION_NODE) && ((DOMProcessingInstruction) this).isProlog(); - } - - public boolean isCDATA() { - return getNodeType() == DOMNode.CDATA_SECTION_NODE; - } - - public boolean isDoctype() { - return getNodeType() == DOMNode.DOCUMENT_TYPE_NODE; - } - - public boolean isGenericDTDDecl() { - return getNodeType() == DOMNode.DTD_DECL_NODE; - } - - public boolean isElement() { - return getNodeType() == DOMNode.ELEMENT_NODE; - } - - public boolean isAttribute() { - return getNodeType() == DOMNode.ATTRIBUTE_NODE; - } - - public boolean isText() { - return getNodeType() == DOMNode.TEXT_NODE; - } - - public boolean isCharacterData() { - return isCDATA() || isText() || isProcessingInstruction() || isComment(); - } - - public boolean isDTDElementDecl() { - return getNodeType() == DOMNode.DTD_ELEMENT_DECL_NODE; - } - - public boolean isDTDAttListDecl() { - return getNodeType() == DOMNode.DTD_ATT_LIST_NODE; - } - - public boolean isDTDEntityDecl() { - return getNodeType() == Node.ENTITY_NODE; - } - - public boolean isDTDNotationDecl() { - return getNodeType() == DOMNode.DTD_NOTATION_DECL; - } - - public boolean isOwnerDocument() { - return getNodeType() == Node.DOCUMENT_NODE; - } - - public boolean isChildOfOwnerDocument() { - if (parent == null) { - return false; - } - return parent.getNodeType() == Node.DOCUMENT_NODE; - } - - @Override - public int getStart() { - return start; - } - - @Override - public int getEnd() { - return end; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getLocalName() - */ - @Override - public String getLocalName() { - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getParentNode() - */ - @Override - public DOMNode getParentNode() { - return parent; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getFirstChild() - */ - @Override - public DOMNode getFirstChild() { - return this.children != null && children.size() > 0 ? this.children.get(0) : null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getLastChild() - */ - @Override - public DOMNode getLastChild() { - return this.children != null && this.children.size() > 0 ? this.children.get(this.children.size() - 1) : null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getAttributes() - */ - @Override - public NamedNodeMap getAttributes() { - return attributeNodes; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getChildNodes() - */ - @Override - public NodeList getChildNodes() { - return children != null ? children : EMPTY_CHILDREN; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#appendChild(org.w3c.dom.Node) - */ - @Override - public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#cloneNode(boolean) - */ - @Override - public org.w3c.dom.Node cloneNode(boolean deep) { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#compareDocumentPosition(org.w3c.dom.Node) - */ - @Override - public short compareDocumentPosition(org.w3c.dom.Node other) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getBaseURI() - */ - @Override - public String getBaseURI() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getFeature(java.lang.String, java.lang.String) - */ - @Override - public Object getFeature(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - @Override - public String getNamespaceURI() { - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNextSibling() - */ - @Override - public DOMNode getNextSibling() { - DOMNode parentNode = getParentNode(); - if (parentNode == null) { - return null; - } - List children = parentNode.getChildren(); - int nextIndex = children.indexOf(this) + 1; - return nextIndex < children.size() ? children.get(nextIndex) : null; - } - - @Override - public String getNodeValue() throws DOMException { - return null; - } - - @Override - public String getPrefix() { - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getPreviousSibling() - */ - @Override - public DOMNode getPreviousSibling() { - DOMNode parentNode = getParentNode(); - if (parentNode == null) { - return null; - } - List children = parentNode.getChildren(); - int previousIndex = children.indexOf(this) - 1; - return previousIndex >= 0 ? children.get(previousIndex) : null; - } - - public DOMNode getPreviousNonTextSibling() { - DOMNode prev = getPreviousSibling(); - while (prev != null && prev.isText()) { - prev = prev.getPreviousSibling(); - } - return prev; - } - - public DOMElement getOrphanEndElement(int offset, String tagName) { - DOMNode next = getNextSibling(); - if (next == null || !next.isElement()) { - return null; - } - // emp| - DOMElement nextElement = (DOMElement) next; - if (nextElement.isOrphanEndTagOf(tagName)) { - return nextElement; - } - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getTextContent() - */ - @Override - public String getTextContent() throws DOMException { - return getNodeValue(); - } - - @Override - public Object getUserData(String arg0) { - return null; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#hasChildNodes() - */ - @Override - public boolean hasChildNodes() { - return children != null && !children.isEmpty(); - } - - @Override - public org.w3c.dom.Node insertBefore(org.w3c.dom.Node arg0, org.w3c.dom.Node arg1) throws DOMException { - return null; - } - - @Override - public boolean isDefaultNamespace(String arg0) { - return false; - } - - @Override - public boolean isEqualNode(org.w3c.dom.Node arg0) { - return false; - } - - @Override - public boolean isSameNode(org.w3c.dom.Node arg0) { - return false; - } - - @Override - public boolean isSupported(String arg0, String arg1) { - return false; - } - - @Override - public String lookupNamespaceURI(String arg0) { - return null; - } - - @Override - public String lookupPrefix(String arg0) { - return null; - } - - @Override - public void normalize() { - } - - @Override - public org.w3c.dom.Node removeChild(org.w3c.dom.Node arg0) throws DOMException { - return null; - } - - @Override - public org.w3c.dom.Node replaceChild(org.w3c.dom.Node arg0, org.w3c.dom.Node arg1) throws DOMException { - return null; - } - - @Override - public void setNodeValue(String arg0) throws DOMException { - } - - @Override - public void setPrefix(String arg0) throws DOMException { - } - - @Override - public void setTextContent(String arg0) throws DOMException { - } - - @Override - public Object setUserData(String arg0, Object arg1, UserDataHandler arg2) { - return null; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMParser.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMParser.java deleted file mode 100644 index 668083aa0..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMParser.java +++ /dev/null @@ -1,683 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.eclipse.lemminx.commons.BadLocationException; -import org.eclipse.lemminx.commons.TextDocument; -import org.eclipse.lemminx.dom.parser.Scanner; -import org.eclipse.lemminx.dom.parser.TokenType; -import org.eclipse.lemminx.dom.parser.XMLScanner; -import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager; -import org.eclipse.lemminx.utils.DOMUtils; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * Tolerant XML parser. - * - */ -public class DOMParser { - - private static final Logger LOGGER = Logger.getLogger(DOMParser.class.getName()); - - private static final DOMParser INSTANCE = new DOMParser(); - - public static DOMParser getInstance() { - return INSTANCE; - } - - private DOMParser() { - - } - - public DOMDocument parse(String text, String uri, URIResolverExtensionManager resolverExtensionManager) { - return parse(new TextDocument(text, uri), resolverExtensionManager); - } - - public DOMDocument parse(String text, String uri, URIResolverExtensionManager resolverExtensionManager, - boolean ignoreWhitespaceContent) { - return parse(new TextDocument(text, uri), resolverExtensionManager, ignoreWhitespaceContent); - } - - public DOMDocument parse(TextDocument document, URIResolverExtensionManager resolverExtensionManager) { - return parse(document, resolverExtensionManager, true); - } - - public DOMDocument parse(TextDocument document, URIResolverExtensionManager resolverExtensionManager, - boolean ignoreWhitespaceContent) { - return parse(document, resolverExtensionManager, ignoreWhitespaceContent, null); - } - - public DOMDocument parse(TextDocument document, URIResolverExtensionManager resolverExtensionManager, - boolean ignoreWhitespaceContent, CancelChecker monitor) { - boolean isDTD = DOMUtils.isDTD(document.getUri()); - boolean inDTDInternalSubset = false; - String text = document.getText(); - Scanner scanner = XMLScanner.createScanner(text, 0, isDTD); - DOMDocument xmlDocument = new DOMDocument(document, resolverExtensionManager); - xmlDocument.setCancelChecker(monitor); - - DOMNode curr = isDTD ? new DOMDocumentType(0, text.length()) : xmlDocument; - if (isDTD) { - xmlDocument.addChild(curr); - - // This DOMDocumentType object is hidden, and just represents the DTD file - // nothing should affect it's closed status - curr.closed = true; - } - DOMNode lastClosed = curr; - DOMAttr attr = null; - int endTagOpenOffset = -1; - String pendingAttribute = null; - DOMNode tempWhitespaceContent = null; - boolean isInitialDeclaration = true; // A declaration can have multiple internal declarations - boolean previousTokenWasEndTagOpen = false; - TokenType token = scanner.scan(); - while (token != TokenType.EOS) { - if (monitor != null) { - monitor.checkCanceled(); - } - if (tempWhitespaceContent != null && token != TokenType.EndTagOpen) { - tempWhitespaceContent = null; - } - if (previousTokenWasEndTagOpen) { - previousTokenWasEndTagOpen = false; - if (token != TokenType.EndTag) { - // The excepted token is not an EndTag, create a fake end tag element - DOMElement element = xmlDocument.createElement(endTagOpenOffset, endTagOpenOffset + 2); - element.endTagOpenOffset = endTagOpenOffset; - curr.addChild(element); - } - } - switch (token) { - case StartTagOpen: { - if (!curr.isClosed() && curr.parent != null) { - // The next node's parent (curr) is not closed at this point - // so the node's parent (curr) will have its end position updated - // to a newer end position. - curr.end = scanner.getTokenOffset(); - } - if ((curr.isClosed()) || curr.isDoctype()) { - // The next node being considered is a child of 'curr' - // and if 'curr' is already closed then 'curr' was not updated properly. - // Or if we get a Doctype node then we know it was not closed and 'curr' - // wasn't updated properly. - curr = curr.parent; - inDTDInternalSubset = false; // In case it was previously in the internal subset - } - DOMElement child = xmlDocument.createElement(scanner.getTokenOffset(), scanner.getTokenEnd()); - child.startTagOpenOffset = scanner.getTokenOffset(); - curr.addChild(child); - curr = child; - break; - } - - case StartTag: { - DOMElement element = (DOMElement) curr; - element.tag = scanner.getTokenText(); - curr.end = scanner.getTokenEnd(); - break; - } - - case StartTagClose: - if (curr.isElement()) { - DOMElement element = (DOMElement) curr; - curr.end = scanner.getTokenEnd(); // might be later set to end tag position - element.startTagCloseOffset = scanner.getTokenOffset(); - - // never enters isEmptyElement() is always false - if (element.hasTagName() && isEmptyElement(element.getTagName()) && curr.parent != null) { - curr.closed = true; - curr = curr.parent; - } - } else if (curr.isProcessingInstruction() || curr.isProlog()) { - DOMProcessingInstruction element = (DOMProcessingInstruction) curr; - curr.end = scanner.getTokenEnd(); // might be later set to end tag position - element.startTagClose = true; - if (element.getTarget() != null && isEmptyElement(element.getTarget()) && curr.parent != null) { - curr.closed = true; - curr = curr.parent; - } - } - curr.end = scanner.getTokenEnd(); - break; - - case EndTagOpen: - if (tempWhitespaceContent != null) { - curr.addChild(tempWhitespaceContent); - tempWhitespaceContent = null; - } - endTagOpenOffset = scanner.getTokenOffset(); - curr.end = scanner.getTokenOffset(); - previousTokenWasEndTagOpen = true; - break; - - case EndTag: - // end tag (ex: ) - String closeTag = scanner.getTokenText(); - DOMNode current = curr; - - /** - * eg: will set a,b,c end position to the start of | - */ - while (!(curr.isElement() && ((DOMElement) curr).isSameTag(closeTag)) && curr.parent != null) { - curr.end = endTagOpenOffset; - curr = curr.parent; - } - if (curr != xmlDocument) { - curr.closed = true; - if (curr.isElement()) { - ((DOMElement) curr).endTagOpenOffset = endTagOpenOffset; - } else if (curr.isProcessingInstruction() || curr.isProlog()) { - ((DOMProcessingInstruction) curr).endTagOpenOffset = endTagOpenOffset; - } - curr.end = scanner.getTokenEnd(); - } else { - // element open tag not found (ex: ) add a fake element which only has an - // end tag (no start tag). - DOMElement element = xmlDocument.createElement(scanner.getTokenOffset() - 2, scanner.getTokenEnd()); - element.endTagOpenOffset = endTagOpenOffset; - element.tag = closeTag; - current.addChild(element); - curr = element; - } - break; - - case StartTagSelfClose: - if (curr.parent != null) { - curr.closed = true; - ((DOMElement) curr).selfClosed = true; - curr.end = scanner.getTokenEnd(); - lastClosed = curr; - curr = curr.parent; - } - break; - - case EndTagClose: - if (curr.parent != null) { - curr.end = scanner.getTokenEnd(); - lastClosed = curr; - if (lastClosed.isElement()) { - ((DOMElement) curr).endTagCloseOffset = scanner.getTokenOffset(); - } - if (curr.isDoctype()) { - curr.closed = true; - } - curr = curr.parent; - - } - break; - - case AttributeName: { - pendingAttribute = scanner.getTokenText(); - attr = new DOMAttr(pendingAttribute, scanner.getTokenOffset(), - scanner.getTokenOffset() + pendingAttribute.length(), curr); - curr.setAttributeNode(attr); - curr.end = scanner.getTokenEnd(); - break; - } - - case DelimiterAssign: { - if (attr != null) { - // Sets the value to the '=' position in case there is no AttributeValue - attr.setValue(null, scanner.getTokenOffset(), scanner.getTokenEnd()); - attr.setDelimiter(true); - } - break; - } - - case AttributeValue: { - String value = scanner.getTokenText(); - if (curr.hasAttributes() && attr != null) { - attr.setValue(value, scanner.getTokenOffset(), scanner.getTokenOffset() + value.length()); - } - pendingAttribute = null; - attr = null; - curr.end = scanner.getTokenEnd(); - break; - } - - case CDATATagOpen: { - DOMCDATASection cdataNode = xmlDocument.createCDataSection(scanner.getTokenOffset(), text.length()); - curr.addChild(cdataNode); - curr = cdataNode; - break; - } - - case CDATAContent: { - DOMCDATASection cdataNode = (DOMCDATASection) curr; - cdataNode.startContent = scanner.getTokenOffset(); - cdataNode.endContent = scanner.getTokenEnd(); - curr.end = scanner.getTokenEnd(); - break; - } - - case CDATATagClose: { - curr.end = scanner.getTokenEnd(); - curr.closed = true; - curr = curr.parent; - break; - } - - case StartPrologOrPI: { - DOMProcessingInstruction prologOrPINode = xmlDocument - .createProcessingInstruction(scanner.getTokenOffset(), text.length()); - curr.addChild(prologOrPINode); - curr = prologOrPINode; - break; - } - - case PIName: { - DOMProcessingInstruction processingInstruction = ((DOMProcessingInstruction) curr); - processingInstruction.target = scanner.getTokenText(); - processingInstruction.processingInstruction = true; - break; - } - - case PrologName: { - DOMProcessingInstruction processingInstruction = ((DOMProcessingInstruction) curr); - processingInstruction.target = scanner.getTokenText(); - processingInstruction.prolog = true; - break; - } - - case PIContent: { - DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) curr; - processingInstruction.startContent = scanner.getTokenOffset(); - processingInstruction.endContent = scanner.getTokenEnd(); - break; - } - - case PIEnd: - case PrologEnd: { - curr.end = scanner.getTokenEnd(); - curr.closed = true; - curr = curr.parent; - break; - } - - case StartCommentTag: { - // Incase the tag before the comment tag (curr) was not properly closed - // curr should be set to the root node. - if (xmlDocument.isDTD() || inDTDInternalSubset) { - while (!curr.isDoctype()) { - curr = curr.parent; - } - } else if ((curr.isClosed())) { - curr = curr.parent; - } - DOMComment comment = xmlDocument.createComment(scanner.getTokenOffset(), text.length()); - curr.addChild(comment); - curr = comment; - try { - int endLine = document.positionAt(lastClosed.end).getLine(); - int startLine = document.positionAt(curr.start).getLine(); - if (endLine == startLine && lastClosed.end <= curr.start) { - comment.commentSameLineEndTag = true; - } - } catch (BadLocationException e) { - LOGGER.log(Level.SEVERE, "XMLParser StartCommentTag bad offset in document", e); - } - break; - } - - case Comment: { - DOMComment comment = (DOMComment) curr; - comment.startContent = scanner.getTokenOffset(); - comment.endContent = scanner.getTokenEnd(); - break; - } - - case EndCommentTag: { - curr.end = scanner.getTokenEnd(); - curr.closed = true; - curr = curr.parent; - break; - } - - case Content: { - boolean currIsDeclNode = curr instanceof DTDDeclNode; - if (currIsDeclNode) { - curr.end = scanner.getTokenOffset() - 1; - while (!curr.isDoctype()) { - curr = curr.getParentNode(); - } - } - int start = scanner.getTokenOffset(); - int end = scanner.getTokenEnd(); - DOMText textNode = xmlDocument.createText(start, end); - textNode.closed = true; - - if (scanner.isTokenTextBlank()) { - if (ignoreWhitespaceContent) { - if (curr.hasChildNodes()) { - break; - } - - tempWhitespaceContent = textNode; - break; - - } else if (!currIsDeclNode) { - textNode.setWhitespace(true); - } else { - break; - } - - } - - curr.addChild(textNode); - break; - } - - // DTD - - case DTDStartDoctypeTag: { - DOMDocumentType doctype = xmlDocument.createDocumentType(scanner.getTokenOffset(), text.length()); - curr.addChild(doctype); - doctype.parent = curr; - curr = doctype; - break; - } - - case DTDDoctypeName: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDDocTypeKindPUBLIC: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDDocTypeKindSYSTEM: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDDoctypePublicId: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setPublicId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDDoctypeSystemId: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setSystemId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDStartInternalSubset: { - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setStartInternalSubset(scanner.getTokenOffset()); - inDTDInternalSubset = true; - break; - } - - case DTDEndInternalSubset: { - while (!curr.isDoctype()) { - curr.end = scanner.getTokenOffset() - 1; - curr = curr.getParentNode(); - } - inDTDInternalSubset = false; - DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.setEndInternalSubset(scanner.getTokenEnd()); - break; - } - - case DTDStartElement: { - // If previous 'curr' was an unclosed DTD Declaration - while (!curr.isDoctype()) { - curr.end = scanner.getTokenOffset(); - curr = curr.getParentNode(); - } - - DTDElementDecl child = new DTDElementDecl(scanner.getTokenOffset(), text.length()); - curr.addChild(child); - curr = child; - break; - } - - case DTDElementDeclName: { - DTDElementDecl element = (DTDElementDecl) curr; - element.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDElementCategory: { - DTDElementDecl element = (DTDElementDecl) curr; - element.setCategory(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDStartElementContent: { - DTDElementDecl element = (DTDElementDecl) curr; - element.setContent(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDElementContent: { - DTDElementDecl element = (DTDElementDecl) curr; - element.updateLastParameterEnd(scanner.getTokenEnd()); - break; - } - - case DTDEndElementContent: { - DTDElementDecl element = (DTDElementDecl) curr; - element.updateLastParameterEnd(scanner.getTokenEnd()); - break; - } - - case DTDStartAttlist: { - while (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset(); - curr = curr.getParentNode(); - } - DTDAttlistDecl child = new DTDAttlistDecl(scanner.getTokenOffset(), text.length()); - - isInitialDeclaration = true; - curr.addChild(child); - curr = child; - break; - } - - case DTDAttlistElementName: { - DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDAttlistAttributeName: { - DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - if (isInitialDeclaration == false) { - // All additional declarations are created as new DTDAttlistDecl's - DTDAttlistDecl child = new DTDAttlistDecl(attribute.getStart(), attribute.getEnd()); - attribute.addAdditionalAttDecl(child); - child.parent = attribute; - - attribute = child; - curr = child; - } - attribute.setAttributeName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDAttlistAttributeType: { - DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.setAttributeType(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDAttlistAttributeValue: { - DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.setAttributeValue(scanner.getTokenOffset(), scanner.getTokenEnd()); - - if (attribute.parent.isDTDAttListDecl()) { // Is not the root/main ATTLIST node - curr = attribute.parent; - } else { - isInitialDeclaration = false; - } - break; - } - - case DTDStartEntity: { - while (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset(); - curr = curr.getParentNode(); - } - DTDEntityDecl child = new DTDEntityDecl(scanner.getTokenOffset(), text.length()); - curr.addChild(child); - curr = child; - break; - } - - case DTDEntityPercent: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setPercent(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEntityName: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEntityValue: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setValue(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEntityKindPUBLIC: - case DTDEntityKindSYSTEM: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEntityPublicId: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setPublicId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEntitySystemId: { - DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.setSystemId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDStartNotation: { - while (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset(); - curr = curr.getParentNode(); - } - DTDNotationDecl child = new DTDNotationDecl(scanner.getTokenOffset(), text.length()); - curr.addChild(child); - curr = child; - isInitialDeclaration = true; - break; - } - - case DTDNotationName: { - DTDNotationDecl notation = (DTDNotationDecl) curr; - notation.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDNotationKindPUBLIC: { - DTDNotationDecl notation = (DTDNotationDecl) curr; - notation.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDNotationKindSYSTEM: { - DTDNotationDecl notation = (DTDNotationDecl) curr; - notation.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDNotationPublicId: { - DTDNotationDecl notation = (DTDNotationDecl) curr; - notation.setPublicId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDNotationSystemId: { - DTDNotationDecl notation = (DTDNotationDecl) curr; - notation.setSystemId(scanner.getTokenOffset(), scanner.getTokenEnd()); - break; - } - - case DTDEndTag: { - if ((curr.isDTDElementDecl() || curr.isDTDAttListDecl() || curr.isDTDEntityDecl() - || curr.isDTDNotationDecl())) { - while (curr.parent != null && !curr.parent.isDoctype()) { - curr = curr.parent; - } - curr.end = scanner.getTokenEnd(); - curr.closed = true; - curr = curr.parent; - } - break; - } - - case DTDEndDoctypeTag: { - ((DOMDocumentType) curr).end = scanner.getTokenEnd(); - curr.closed = true; - curr = curr.parent; - break; - } - - case DTDUnrecognizedParameters: { - DTDDeclNode node = (DTDDeclNode) curr; - node.setUnrecognized(scanner.getTokenOffset(), ((XMLScanner) scanner).getLastNonWhitespaceOffset()); - break; - } - - default: - } - token = scanner.scan(); - } - if (previousTokenWasEndTagOpen) { - previousTokenWasEndTagOpen = false; - if (token != TokenType.EndTag) { - // The excepted token is not an EndTag, create a fake end tag element - DOMElement element = xmlDocument.createElement(endTagOpenOffset, endTagOpenOffset + 2); - element.endTagOpenOffset = endTagOpenOffset; - curr.addChild(element); - } - } - while (curr.parent != null) { - curr.end = text.length(); - curr = curr.parent; - } - return xmlDocument; - } - - private static boolean isEmptyElement(String tag) { - return false; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMProcessingInstruction.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMProcessingInstruction.java deleted file mode 100644 index 1463e8809..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMProcessingInstruction.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import org.w3c.dom.DOMException; - -/** - * A processing instruction node. - * - */ -public class DOMProcessingInstruction extends DOMCharacterData implements org.w3c.dom.ProcessingInstruction { - - boolean startTagClose; - String target; - boolean prolog = false; - boolean processingInstruction = false; - int startContent; - int endContent; - int endTagOpenOffset = NULL_VALUE; - - public DOMProcessingInstruction(int start, int end) { - super(start, end); - } - - public boolean isProlog() { - return prolog; - } - - public boolean isProcessingInstruction() { - return processingInstruction; - } - - public int getStartContent() { - return startContent; - } - - public int getEndContent() { - return endContent; - } - - /** - * Returns the end tag start offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - * - * @return the end tag start offset and {@link DOMNode#NULL_VALUE} if it doesn't - * exist. - */ - public int getEndTagStart() { - return endTagOpenOffset; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.PROCESSING_INSTRUCTION_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return getTarget(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.ProcessingInstruction#getTarget() - */ - @Override - public String getTarget() { - return target; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.ProcessingInstruction#getData() - */ - @Override - public String getData() { - return super.getData().trim(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.ProcessingInstruction#setData(java.lang.String) - */ - @Override - public void setData(String data) throws DOMException { - throw new UnsupportedOperationException(); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMRange.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMRange.java deleted file mode 100644 index 725aae4be..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMRange.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2019 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.dom; - -/** - * DOM range - * - * @author Angelo ZERR - * - */ -public interface DOMRange { - - /** - * Returns the start offset of the node. - * - * @return the start offset of the node. - */ - int getStart(); - - /** - * Returns the end offset of the node. - * - * @return the end offset of the node. - */ - int getEnd(); - - /** - * Returns the owner document. - * - * @return the owner document. - */ - DOMDocument getOwnerDocument(); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMText.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMText.java deleted file mode 100644 index e4f66a235..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DOMText.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import org.w3c.dom.DOMException; - -/** - * A Text node. - * - */ -public class DOMText extends DOMCharacterData implements org.w3c.dom.Text { - - public DOMText(int start, int end) { - super(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeType() - */ - @Override - public short getNodeType() { - return DOMNode.TEXT_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Node#getNodeName() - */ - @Override - public String getNodeName() { - return "#text"; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Text#getWholeText() - */ - @Override - public String getWholeText() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Text#isElementContentWhitespace() - */ - @Override - public boolean isElementContentWhitespace() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Text#replaceWholeText(java.lang.String) - */ - @Override - public DOMText replaceWholeText(String content) throws DOMException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Text#splitText(int) - */ - @Override - public DOMText splitText(int offset) throws DOMException { - throw new UnsupportedOperationException(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDAttlistDecl.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDAttlistDecl.java deleted file mode 100644 index 7daf7d386..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDAttlistDecl.java +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import java.util.ArrayList; -import java.util.List; - -/** - * DTD Attribute List declaration "" - * - * or - * - *
-	 * 
-	 * 
-	 * >
-	 */
-
-	public DTDDeclParameter attributeName;
-	public DTDDeclParameter attributeType;
-	public DTDDeclParameter attributeValue;
-
-	private List internalChildren; // Holds all additional internal attlist declaractions
-
-	public DTDAttlistDecl(int start, int end) {
-		super(start, end);
-		setDeclType(start + 2, start + 9);
-	}
-
-	@Override
-	public String getNodeName() {
-		return getAttributeName();
-	}
-
-	/**
-	 * Returns the element name
-	 * 
-	 * @return the element name
-	 */
-	public String getElementName() {
-		return getName();
-	}
-
-	/**
-	 * Returns the attribute name
-	 * 
-	 * @return the attribute name
-	 */
-	public String getAttributeName() {
-		return attributeName != null ? attributeName.getParameter() : null;
-	}
-
-	public void setAttributeName(int start, int end) {
-		attributeName = addNewParameter(start, end);
-	}
-
-	public String getAttributeType() {
-		return attributeType != null ? attributeType.getParameter() : null;
-	}
-
-	public void setAttributeType(int start, int end) {
-		attributeType = addNewParameter(start, end);
-	}
-
-	public String getAttributeValue() {
-		return attributeValue != null ? attributeValue.getParameter() : null;
-	}
-
-	public void setAttributeValue(int start, int end) {
-		attributeValue = addNewParameter(start, end);
-	}
-
-	@Override
-	public short getNodeType() {
-		return DOMNode.DTD_ATT_LIST_NODE;
-	}
-
-	/**
-	 * Add another internal attlist declaration to the list of children.
-	 * 
-	 * An ATTLIST decl can internally declare multiple declarations, see top of
-	 * file. This will add another one to its list of additional declarations.
-	 */
-	void addAdditionalAttDecl(DTDAttlistDecl child) {
-		if (internalChildren == null) {
-			internalChildren = new ArrayList<>();
-		}
-		internalChildren.add(child);
-	}
-
-	public List getInternalChildren() {
-		return internalChildren;
-	}
-
-	/**
-	 * Returns true if this node's parent is the Doctype node.
-	 * 
-	 * 
-	 * This is used because an Attlist declaration can have multiple attribute
-	 * declarations within a tag that are each represented by this class.
-	 */
-	public boolean isRootAttlist() {
-		return this.parent.isDoctype();
-	}
-
-}
diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDDeclNode.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDDeclNode.java
deleted file mode 100644
index 18dbde395..000000000
--- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDDeclNode.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2018 Red Hat Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v20.html
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- *     Red Hat Inc. - initial API and implementation
- *
- *******************************************************************************/
-package org.eclipse.lemminx.dom;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.w3c.dom.Node;
-
-/**
- * DTDNode
- */
-public class DTDDeclNode extends DOMNode {
-
-	/**
-	 * This class is the base for all declaration nodes for DTD's.
-	 * 
-	 * It can also be used to represent an undefined tag, meaning it is not any of:
-	 * ELEMENT, ATTLIST, ENTITY, or NOTATION
-	 */
-
-	public DTDDeclParameter unrecognized; // holds all content after parsing goes wrong in a DTD declaration (ENTITY,
-											// ATTLIST, ...).
-	public DTDDeclParameter declType; // represents the actual name of the decl eg: ENTITY, ATTLIST, ...
-
-	private List parameters;
-	private DTDDeclParameter name;
-
-	public DTDDeclNode(int start, int end) {
-		super(start, end);
-	}
-
-	public String getName() {
-		DTDDeclParameter name = getNameParameter();
-		return name != null ? name.getParameter() : null;
-	}
-
-	public DTDDeclParameter getNameParameter() {
-		return name;
-	}
-
-	protected DTDDeclParameter getParameterAtIndex(int index) {
-		return parameters != null && parameters.size() > index ? parameters.get(index) : null;
-	}
-
-	public void setName(int start, int end) {
-		name = addNewParameter(start, end);
-	}
-
-	public boolean isInNameParameter(int offset) {
-		DTDDeclParameter name = getNameParameter();
-		return DOMNode.isIncluded(name, offset);
-	}
-
-	public DOMDocumentType getOwnerDocType() {
-		Node node = parent;
-		while (node != null) {
-			if (node.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
-				return (DOMDocumentType) node;
-			}
-			node = node.getParentNode();
-		}
-		return null;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see org.w3c.dom.Node#getNodeName()
-	 */
-	@Override
-	public String getNodeName() {
-		return getName();
-	}
-
-	@Override
-	public short getNodeType() {
-		return DOMNode.DTD_DECL_NODE;
-	}
-
-	public String getUnrecognized() {
-		return unrecognized.getParameter();
-	}
-
-	public void setUnrecognized(int start, int end) {
-		unrecognized = addNewParameter(start, end);
-	}
-
-	public DTDDeclParameter addNewParameter(int start, int end) {
-		if (parameters == null) {
-			parameters = new ArrayList<>();
-		}
-		DTDDeclParameter parameter = new DTDDeclParameter(this, start, end);
-		parameters.add(parameter);
-		this.end = end; // updates end position of the node.
-		return parameter;
-	}
-
-	public void updateLastParameterEnd(int end) {
-		if (parameters != null && parameters.size() > 0) {
-			DTDDeclParameter last = parameters.get(parameters.size() - 1);
-			last.end = end;
-			this.end = end;
-		}
-	}
-
-	public List getParameters() {
-		if (parameters == null) {
-			parameters = new ArrayList<>();
-		}
-		return parameters;
-	}
-
-	public void setDeclType(int start, int end) {
-		declType = new DTDDeclParameter(this, start, end);
-	}
-
-	public String getDeclType() {
-		if (declType != null) {
-			return declType.getParameter();
-		}
-		return null;
-	}
-
-	/**
-	 * Returns the parameter name which references a DTD element declaration
-	 * (
-	 * 
-	 * 
-	 * @param offset the offset
-	 * @return the parameter name which references a DTD element declaration
-	 *         ( - initial API and implementation
- */
-package org.eclipse.lemminx.dom;
-
-import static org.eclipse.lemminx.utils.StringUtils.findEndWord;
-import static org.eclipse.lemminx.utils.StringUtils.findStartWord;
-
-import java.util.function.BiConsumer;
-import java.util.function.Predicate;
-
-/**
- * DTD Element Declaration  isValidChar = (c) -> Character.isJavaIdentifierPart(c) || c == '-';
-
-	/**
-	 * Formats:
-	 * 
-	 *  or 
-	 * 
-	 */
-
-	public DTDDeclParameter category;
-	public DTDDeclParameter content;
-
-	public DTDElementDecl(int start, int end) {
-		super(start, end);
-		setDeclType(start + 2, start + 9);
-	}
-
-	@Override
-	public String getNodeName() {
-		return getName();
-	}
-
-	public String getCategory() {
-		return category != null ? category.getParameter() : null;
-	}
-
-	public void setCategory(int start, int end) {
-		category = addNewParameter(start, end);
-	}
-
-	public String getContent() {
-		return content != null ? content.getParameter() : null;
-	}
-
-	public void setContent(int start, int end) {
-		content = addNewParameter(start, end);
-	}
-
-	@Override
-	public short getNodeType() {
-		return DOMNode.DTD_ELEMENT_DECL_NODE;
-	}
-
-	/**
-	 * Returns the offset of the end of tag 
-	 *  will return (start/end offset) of
-	 * heading.
-	 * 

- * - *

- * will return null. - *

- * - * @param offset the offset - * @return the parameter (start/end offset) at the given offset and null - * otherwise. - */ - public DTDDeclParameter getParameterAt(int offset) { - // Check if offset is in the collector) { - DTDDeclParameter name = getNameParameter(); - if (name == null) { - return; - } - int start = name.getEnd(); - int end = getEnd(); - - String text = getOwnerDocument().getText(); - int wordStart = -1; - int wordEnd = -1; - // Loop for content after text which starts at - * wordStart offset and ends at wordEnd matches the - * given searchWord - * - * @param searchWord the word to search - * @param text the text - * @param wordStart the word start offset - * @param wordEnd the word end offset - * @return true if the word in the given text which starts at - * wordStart offset and ends at wordEnd - * matches the given searchName - */ - private static boolean isMatchName(String searchWord, String text, int wordStart, int wordEnd) { - int length = wordEnd - wordStart; - if (searchWord.length() != length) { - return false; - } - for (int j = 0; j < length; j++) { - if ((searchWord.charAt(j) != text.charAt(wordStart + j))) { - return false; - } - } - return true; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDEntityDecl.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDEntityDecl.java deleted file mode 100644 index 6541cc44b..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDEntityDecl.java +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import org.w3c.dom.Entity; -import org.w3c.dom.Node; - -/** - * DOM Entity declaration - * - * or - * - * - * - * or - * - * - * - * or - * - * - * - * or - * - * - * - * or - * - * - */ - DTDDeclParameter percent; - DTDDeclParameter value; - DTDDeclParameter kind; - DTDDeclParameter publicId; - DTDDeclParameter systemId; - - public DTDEntityDecl(int start, int end) { - super(start, end); - setDeclType(start + 2, start + 8); - } - - public String getPercent() { - return percent != null ? percent.getParameter() : null; - } - - public void setPercent(int start, int end) { - percent = addNewParameter(start, end); - } - - public String getValue() { - return value != null ? value.getParameterWithoutFirstAndLastChar() : null; - } - - public void setValue(int start, int end) { - value = addNewParameter(start, end); - } - - public String getKind() { - return kind != null ? kind.getParameter() : null; - } - - public void setKind(int start, int end) { - kind = addNewParameter(start, end); - } - - @Override - public short getNodeType() { - return Node.ENTITY_NODE; - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getInputEncoding() - */ - @Override - public String getInputEncoding() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getNotationName() - */ - @Override - public String getNotationName() { - return getValue(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getPublicId() - */ - @Override - public String getPublicId() { - return publicId != null ? publicId.getParameterWithoutFirstAndLastChar() : null; - } - - public void setPublicId(int start, int end) { - publicId = addNewParameter(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getSystemId() - */ - @Override - public String getSystemId() { - return systemId != null ? systemId.getParameterWithoutFirstAndLastChar() : null; - } - - public void setSystemId(int start, int end) { - systemId = addNewParameter(start, end); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getXmlEncoding() - */ - @Override - public String getXmlEncoding() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.w3c.dom.Entity#getXmlVersion() - */ - @Override - public String getXmlVersion() { - throw new UnsupportedOperationException(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDNotationDecl.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDNotationDecl.java deleted file mode 100644 index 36131e152..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/DTDNotationDecl.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Red Hat Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.lemminx.dom; - -/** - * DTDNotationDecl - */ -public class DTDNotationDecl extends DTDDeclNode { - - /** - * Format: - * - * - * - * or - * - * - * - * or - * - * - */ - - DTDDeclParameter kind; - DTDDeclParameter publicId; - DTDDeclParameter systemId; - - public DTDNotationDecl(int start, int end) { - super(start, end); - setDeclType(start + 2, start + 10); - } - - void setKind(int start, int end) { - kind = addNewParameter(start, end); - } - - public String getKind() { - return kind != null ? kind.getParameter() : null; - } - - void setPublicId(int start, int end) { - publicId = addNewParameter(start, end); - } - - public String getPublicId() { - return publicId != null ? publicId.getParameterWithoutFirstAndLastChar() : null; - } - - void setSystemId(int start, int end) { - systemId = addNewParameter(start, end); - } - - public String getSystemId() { - return systemId != null ? systemId.getParameterWithoutFirstAndLastChar() : null; - } - - @Override - public short getNodeType() { - return DOMNode.DTD_NOTATION_DECL; - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/LineIndentInfo.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/LineIndentInfo.java deleted file mode 100644 index 4e52b9488..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/LineIndentInfo.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Red Hat Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr. - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.lemminx.dom; - -public class LineIndentInfo { - - private final String lineDelimiter; - private final String whitespacesIndent; - - public LineIndentInfo(String lineDelimiter, String whitespacesIndent) { - this.lineDelimiter = lineDelimiter; - this.whitespacesIndent = whitespacesIndent; - } - - public String getLineDelimiter() { - return lineDelimiter; - } - - public String getWhitespacesIndent() { - return whitespacesIndent; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/NoNamespaceSchemaLocation.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/NoNamespaceSchemaLocation.java deleted file mode 100644 index ee89b0d7d..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/NoNamespaceSchemaLocation.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -/** - * - * The declared "xsi:noNamespaceSchemaLocation" - */ -public class NoNamespaceSchemaLocation { - - private final DOMAttr attr; - - public NoNamespaceSchemaLocation(DOMAttr attr) { - this.attr = attr; - } - - public DOMAttr getAttr() { - return attr; - } - - /** - * Returns the location declared in the attribute value of - * "xsi:noNamespaceSchemaLocation" - * - * @return the location declared in the attribute value of - * "xsi:noNamespaceSchemaLocation" - */ - public String getLocation() { - return attr.getValue(); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java deleted file mode 100644 index d34342f02..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocation.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * - * The declared "xsi:schemaLocation" - */ -public class SchemaLocation { - - private final Map schemaLocationValuePairs; - - private final DOMAttr attr; - - // The text to match is of the form: - // http://example.org/schema/root root.xsd http://example.org/schema/bison bison.xsd http://example.org/schema/potato potato.xsd - private static final Pattern SCHEMA_LOCATION_PAIR_PATTERN = Pattern.compile("\\s*([^\\s]+)\\s+([^\\s]+)\\s*"); - - public SchemaLocation(DOMAttr attr) { - this.attr = attr; - this.schemaLocationValuePairs = new HashMap<>(); - String value = attr.getValue(); - Matcher locPairMatcher = SCHEMA_LOCATION_PAIR_PATTERN.matcher(value); - while (locPairMatcher.find()) { - String namespaceURI = locPairMatcher.group(1); - String locationHint = locPairMatcher.group(2); - if (namespaceURI == null || locationHint == null) { - break; - } - DOMNode valNode = attr.getNodeAttrValue(); - // http://example.org/schema/root |root.xsd http://example.org/schema/bison bison.xsd - int start = valNode.getStart() + locPairMatcher.start(2) + 1; - // http://example.org/schema/root root.xsd| http://example.org/schema/bison bison.xsd - int end = valNode.getStart() + locPairMatcher.end(2) + 1; - schemaLocationValuePairs.put(namespaceURI, - new SchemaLocationHint(start, end, locationHint, this)); - } - } - - /** - * Returns the location hint, as a string, that is associated with the given namespace URI. - * - * If the given namespace URI was not referred to in this xsi:schemaLocation, then null is returned. - * - * @param namespaceURI The namespace URI to find the location hint for - * @return The associated location hint, as a string, or null - * if the namespace was not referred to in xsi:schemaLocation - */ - public SchemaLocationHint getLocationHint(String namespaceURI) { - return schemaLocationValuePairs.get(namespaceURI); - } - - public DOMAttr getAttr() { - return attr; - } - - /** - * Returns all the location hints given in this xsi:schemaLocation attribute - * - * @return A Collection of all the location hints as SchemaLocationHint - */ - public Collection getSchemaLocationHints() { - return schemaLocationValuePairs.values(); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java deleted file mode 100644 index 497a14a41..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/SchemaLocationHint.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2020 Red Hat Inc. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -/** - * Represents one of the location hints provided in an xsi:schemaLocation - * attribute. - */ -public class SchemaLocationHint implements DOMRange { - - private final int start, end; - - private final String hint; - - private final SchemaLocation parent; - - /** - * Create a new SchemaLocationHint object that represents one of the location - * hints given in the parent SchemaLocation. - * - * @param start The offset from the beginning of the document where this - * location hint starts - * @param end The offset from the beginning of the document where this - * location hint ends - * @param hint The hint to the location of a schema (A URI that points to a - * schema) - * @param parent The SchemaLocation in which this hint was given - */ - public SchemaLocationHint(int start, int end, String hint, SchemaLocation parent) { - this.start = start; - this.end = end; - this.hint = hint; - this.parent = parent; - } - - /** - * Returns the location hint that this SchemaLocationHint represents - * - * @return The location hint, a URI to a schema, as a String - */ - public String getHint() { - return this.hint; - } - - /** - * Returns the offset from the beginning of the document where this location - * hint starts - * - * @return The offset from the beginning of the document where this location - * hint starts - */ - @Override - public int getStart() { - return this.start; - } - - /** - * Returns the offset from the beginning of the document where this location - * hint ends - * - * @return The offset from the beginning of the document where this location - * hint ends - */ - @Override - public int getEnd() { - return this.end; - } - - @Override - public DOMDocument getOwnerDocument() { - return parent.getAttr().getOwnerDocument(); - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/TargetRange.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/TargetRange.java deleted file mode 100644 index df0532012..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/TargetRange.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2020 Red Hat, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - */ -package org.eclipse.lemminx.dom; - -import org.eclipse.lsp4j.Range; - -/** - * Target range API. - * - */ -public interface TargetRange { - - /** - * Returns the target range. - * - * @return the target range. - */ - Range getTargetRange(); - - /** - * Returns the target URI. - * - * @return the target URI. - */ - String getTargetURI(); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/XMLModel.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/XMLModel.java deleted file mode 100644 index 6f19125ff..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/XMLModel.java +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.dom; - -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.extensions.xerces.xmlmodel.XMLModelDeclaration; -import org.w3c.dom.ProcessingInstruction; - -/** - * XML model processing instruction. - * - *
- * 	<?xml-model href="http://www.docbook.org/xml/5.0/xsd/docbook.xsd"?>
- * 
- * - * - * @see https://www.w3.org/TR/xml-model/ - */ -public class XMLModel { - - private static final String XML_MODEL_PI = "xml-model"; - - private final DOMProcessingInstruction processingInstruction; - private XMLModelDeclaration declaration; - - private DOMRange hrefNode; - - private static class SimpleDOMRange implements DOMRange { - - private final int start; - - private final int end; - - private final DOMDocument ownerDocument; - - public SimpleDOMRange(int start, int end, DOMDocument ownerDocument) { - this.start = start; - this.end = end; - this.ownerDocument = ownerDocument; - } - - @Override - public int getStart() { - return start; - } - - @Override - public int getEnd() { - return end; - } - - @Override - public DOMDocument getOwnerDocument() { - return ownerDocument; - } - - } - - public XMLModel(DOMProcessingInstruction processingInstruction) { - this.processingInstruction = processingInstruction; - } - - /** - * Returns the location of the referenced schema - * - * @return the location of the referenced schema - */ - public String getHref() { - XMLModelDeclaration declaration = getModelDeclaration(); - return declaration != null ? declaration.getHref() : null; - } - - private XMLModelDeclaration getModelDeclaration() { - String data = processingInstruction.getData(); - if (data == null) { - return null; - } - if (declaration == null) { - declaration = XMLModelDeclaration.parse(data.toCharArray(), 0, data.length()); - } - return declaration; - } - - /** - * Returns the declared xml-model list. - * - * @param document the DOM document. - * - * @return the declared xml-model list. - */ - static List createXMLModels(DOMDocument document) { - List children = document.getChildren(); - if (children != null && !children.isEmpty()) { - return children.stream().filter(XMLModel::isXMLModel) - .map(node -> new XMLModel((DOMProcessingInstruction) node)).collect(Collectors.toList()); - } - return Collections.emptyList(); - } - - /** - * Returns true if the given node is a xml-model processing instruction and - * false otherwise. - * - * @param node the DOM node. - * @return true if the given node is a xml-model processing instruction and - * false otherwise. - */ - public static boolean isXMLModel(DOMNode node) { - return node.isProcessingInstruction() && XML_MODEL_PI.equals(((ProcessingInstruction) node).getTarget()); - } - - /** - * Returns the href range and null otherwise. - * - * @return the href range and null otherwise. - */ - public DOMRange getHrefNode() { - if (hrefNode == null) { - XMLModelDeclaration declaration = getModelDeclaration(); - if (declaration == null || declaration.getHref() == null) { - return null; - } - int start = processingInstruction.getStartContent() + declaration.getHrefOffset() - 1; - int end = start + declaration.getHref().length() + 2; - hrefNode = new SimpleDOMRange(start, end, processingInstruction.getOwnerDocument()); - } - return hrefNode; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Constants.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Constants.java deleted file mode 100644 index f09d14601..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Constants.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom.parser; - -import java.util.regex.Pattern; - -public class Constants { - - public final static int _EXL = "!".codePointAt(0); - public final static int _MIN = "-".codePointAt(0); - public final static int _UDS = "_".codePointAt(0); - public final static int _DDT = ":".codePointAt(0); - public final static int _DOT = ".".codePointAt(0); - public final static int _LAN = "<".codePointAt(0); - public final static int _RAN = ">".codePointAt(0); - public final static int _FSL = "/".codePointAt(0); - public final static int _EQS = "=".codePointAt(0); - public final static int _CMA = ",".codePointAt(0); - public final static int _DQO = "\"".codePointAt(0); - public final static int _SQO = "\"".codePointAt(0); - public final static int _SIQ = "\'".codePointAt(0); - public final static int _NWL = "\n".codePointAt(0); - public final static int _CAR = "\r".codePointAt(0); - public final static int _LFD = "\f".codePointAt(0); - public final static int _WSP = " ".codePointAt(0); - public final static int _TAB = "\t".codePointAt(0); - public final static int _OSB = "[".codePointAt(0); - public final static int _CSB = "]".codePointAt(0); - public final static int _ORB = "(".codePointAt(0); - public final static int _CRB = ")".codePointAt(0); - public final static int _OCB = "{".codePointAt(0); - public final static int _CCB = "}".codePointAt(0); - public final static int _CVL = "C".codePointAt(0); - public final static int _DVL = "D".codePointAt(0); - public final static int _AVL = "A".codePointAt(0); - public final static int _TVL = "T".codePointAt(0); - public final static int _OVL = "O".codePointAt(0); - public final static int _YVL = "Y".codePointAt(0); - public final static int _PVL = "P".codePointAt(0); - public final static int _EVL = "E".codePointAt(0); - public final static int _LVL = "L".codePointAt(0); - public final static int _MVL = "M".codePointAt(0); - public final static int _NVL = "N".codePointAt(0); - public final static int _IVL = "I".codePointAt(0); - public final static int _SVL = "S".codePointAt(0); - public final static int _QMA = "?".codePointAt(0); - public final static int _XVL = "x".codePointAt(0); - public final static int _mVL = "m".codePointAt(0); - public final static int _lVL = "l".codePointAt(0); - public final static int _PCT = "%".codePointAt(0); - public final static int _AST = "*".codePointAt(0); - public final static int _PLS = "+".codePointAt(0); - - public static final Pattern ENTITY_NAME_REGEX = Pattern.compile(""); - - public static final Pattern ELEMENT_NAME_REGEX = Pattern.compile("^[_:\\w][_:\\w-.\\d]*"); - - public static final Pattern ATTRIBUTE_NAME_REGEX = Pattern.compile("^[^\\s\\?\"'<>/=\\x00-\\x0F\\x7F\\x80-\\x9F]*"); - - public static final Pattern ATTRIBUTE_VALUE_REGEX = Pattern.compile("^(\"[^\"]*\"?)|(\'[^\']*\'?)"); - - public static final Pattern URL_VALUE_REGEX = Pattern.compile("^(\"[^<>\"]*\")|(\'[^<>\']*\')"); - - public static final Pattern PROLOG_NAME_OPTIONS = Pattern.compile("^(xml)[\\s<>?]?"); - - public static final Pattern PI_TAG_NAME = Pattern.compile("^[a-zA-Z0-9]+"); - - // Add coming processing instructions that are defined to have attributes as - // content - public static final Pattern PI_WITH_VARIABLES = Pattern.compile("^(xml-stylesheet)[\\s<>?]?"); - - public static final Pattern DOCTYPE_KIND_OPTIONS = Pattern.compile("^(PUBLIC|SYSTEM)([\\s<>\"'])"); - - public static final Pattern DTD_ELEMENT_CATEGORY = Pattern.compile("^(EMPTY|ANY)([\\s<>\"'])"); - - public static final Pattern DTD_ELEMENT_CONTENT = Pattern.compile("^(\\((([^\\s,]+,)*[^\\s,]+)\\))|\\(\\)"); - - public static final Pattern DTD_PCDATA = Pattern.compile("^#PCDATA"); - - public static final Pattern DTD_ATTLIST_ATTRIBUTE_TYPE = Pattern - .compile("^(CDATA|IDREFS|IDREF|ID|NMTOKENS|NMTOKEN|ENTITIES|ENTITY|NOTATION|xml:|\\(.*\\))([\\s<>\"'])"); - - public static final Pattern DTD_ATTLIST_ATTRIBUTE_VALUE = Pattern - .compile("^(#REQUIRED|#IMPLIED|\".*\"|#FIXED \".*\")([\\s<>\"'])"); - - public static final Pattern DTD_ENTITY_VALUE = Pattern.compile("^\".*\""); - - public static final Pattern DOCTYPE_NAME = Pattern.compile("^[_:\\w][_:\\w-.\\d]*"); - - public static final Pattern DOCUMENTATION_CONTENT = Pattern.compile(".*<[\\S]+:?documentation[^\\>]*>(.*)<\\/[\\S]+:?documentation[\\s]*>.*"); - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/MultiLineStream.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/MultiLineStream.java deleted file mode 100644 index b6f9a4a13..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/MultiLineStream.java +++ /dev/null @@ -1,336 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom.parser; - -import static org.eclipse.lemminx.dom.parser.Constants._CAR; -import static org.eclipse.lemminx.dom.parser.Constants._CSB; -import static org.eclipse.lemminx.dom.parser.Constants._LAN; -import static org.eclipse.lemminx.dom.parser.Constants._LFD; -import static org.eclipse.lemminx.dom.parser.Constants._NWL; -import static org.eclipse.lemminx.dom.parser.Constants._OSB; -import static org.eclipse.lemminx.dom.parser.Constants._RAN; -import static org.eclipse.lemminx.dom.parser.Constants._TAB; -import static org.eclipse.lemminx.dom.parser.Constants._WSP; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Predicate; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Multi line stream. - * - */ -public class MultiLineStream { - - private static final Predicate WHITESPACE_PREDICATE = ch -> { - return ch == _WSP || ch == _TAB || ch == _NWL || ch == _LFD || ch == _CAR; - }; - - private final String source; - private final int len; - private int position; - private final Map regexpCache; - - public MultiLineStream(String source, int position) { - this.source = source; - this.len = source.length(); - this.position = position; - this.regexpCache = new HashMap<>(); - } - - public boolean eos() { - return this.len <= this.position; - } - - public String getSource() { - return this.source; - } - - public int pos() { - return this.position; - } - - public void goBackTo(int pos) { - this.position = pos; - } - - public void goBack(int n) { - this.position -= n; - } - - public void advance(int n) { - this.position += n; - } - - public void goToEnd() { - this.position = len; - } - - /* - * public int nextChar() { // return this.source.codePointAt(this.position++) || - * 0; int next = this.source.codePointAt(this.position++); return next >= 0 ? - * next : 0; } - */ - - public int peekChar() { - return peekChar(0); - } - - /** - * Peeks at next char at position + n. peekChar() == peekChar(0) - * @param n - * @return - */ - public int peekChar(int n) { - int pos = this.position + n; - if (pos >= len) { - return -1; - } - return this.source.codePointAt(pos); - } - - /** - * Peeks at the char at position 'offset' of the whole document - * @param offset - * @return - */ - public int peekCharAtOffset(int offset) { - if (offset >= len || offset < 0) { - return -1; - } - return this.source.codePointAt(offset); - } - - public boolean advanceIfChar(int ch) { - if (ch == peekChar()) { - this.position++; - return true; - } - return false; - } - - public boolean advanceIfChars(int... ch) { - int i; - if (this.position + ch.length > this.len) { - return false; - } - for (i = 0; i < ch.length; i++) { - if (peekChar(i) != ch[i]) { - return false; - } - } - this.advance(i); - return true; - } - - public int advanceIfAnyOfChars(int... ch) { - int i; - if (this.position + 1 > this.len) { - return -1; - } - for (i = 0; i < ch.length; i++) { - if (advanceIfChar(ch[i])) { - return ch[i]; - } - } - return -1; - } - - public String advanceIfRegExp(Pattern regex) { - Matcher match = getCachedMatcher(regex); - // Initialize start region where search must be started. - match.region(this.position, this.len); - if (match.find()) { - this.position = match.end(); - return match.group(0); - } - return ""; - } - - /** - * Advances stream on regex, but will grab the first group - * @param regex - * @return - */ - public String advanceIfRegExpGroup1(Pattern regex) { - Matcher match = getCachedMatcher(regex); - // Initialize start region where search must be started. - match.region(this.position, this.len); - if (match.find()) { - this.position = match.end(1); - return match.group(1); - } - return ""; - } - - /** - * Advances stream.position no matter what until it hits ch or eof(this.len) - * - * @return boolean: was the char found - */ - public boolean advanceUntilChar(int ch) { - while (this.position < this.len) { - if (peekChar() == ch) { - return true; - } - this.advance(1); - } - return false; - } - - /** - * Will advance until any of the provided chars are encountered - */ - public boolean advanceUntilAnyOfChars(int... ch) { - while (this.position < this.len) { - for (int i = 0; i < ch.length; i++) { - if (peekChar() == ch[i]) { - return true; - } - } - - this.advance(1); - } - return false; - } - - /** - * Will advance the stream position until ch or '<' - */ - public boolean advanceUntilCharOrNewTag(int ch) { - while (this.position < this.len) { - if (peekChar() == ch || peekChar() == _LAN) { - return true; - } - this.advance(1); - } - return false; - } - - /** - * Will advance the stream position until 'closingBracket' or using a stack - * to consider possible open/closed bracket pairs in between. - * - * 'closingBracket' should be the closing bracket eg: > | ] - */ - public boolean advanceUntilCharUsingStack(int closingBracket) { - - int openingBracket; - if(closingBracket == _RAN) { // > - openingBracket = _LAN;// < - } - else if(closingBracket == _CSB) { // ] - openingBracket = _OSB; // [ - } - else { - return false; // The provided closingBracket is not implemented - } - int stack = 0; - while (this.position < this.len) { - if(peekChar() == openingBracket) { - stack ++; - } - else if(peekChar() == closingBracket) { - if(stack == 0) { - return true; - } - stack--; - } - this.advance(1); - } - return false; - } - - public boolean advanceUntilChars(int... ch) { - while (this.position + ch.length <= this.len) { - int i = 0; - for (; i < ch.length && peekChar(i) == ch[i]; i++) { - } - if (i == ch.length) { - return true; - } - this.advance(1); - } - this.goToEnd(); - return false; - } - - /** - * Advances until it matches int[] ch OR it hits '<' If this returns true, peek - * if next char is '<' to check which case was hit - */ - public boolean advanceUntilCharsOrNewTag(int... ch) { - while (this.position + ch.length <= this.len) { - int i = 0; - if (peekChar(0) == _LAN) { // < - return true; - } - for (; i < ch.length && peekChar(i) == ch[i]; i++) { - } - if (i == ch.length) { - return true; - } - this.advance(1); - } - this.goToEnd(); - return false; - } - - /** - * Advances until it reaches a whitespace character - */ - public boolean skipWhitespace() { - int n = this.advanceWhileChar(WHITESPACE_PREDICATE); - return n > 0; - } - - public int advanceWhileChar(Predicate condition) { - int posNow = this.position; - while (this.position < this.len && condition.test(peekChar())) { - this.position++; - } - return this.position - posNow; - } - - /** - * Returns the cached matcher from the given regex. - * - * @param regex the regex pattern. - * @return the cached matcher from the given regex. - */ - private Matcher getCachedMatcher(Pattern regex) { - Matcher matcher = regexpCache.get(regex); - if (matcher == null) { - matcher = regex.matcher(source); - regexpCache.put(regex, matcher); - } else { - matcher.reset(); // Cached regex caused issues, needed to reset it. - } - return matcher; - } - - public int getLastNonWhitespaceOffset() { - int posNow = this.position; - while (posNow > 0 && WHITESPACE_PREDICATE.test(peekCharAtOffset(posNow - 1))) { - posNow--; - } - return posNow; - } -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Scanner.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Scanner.java deleted file mode 100644 index 8513acfa0..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/Scanner.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom.parser; - -/** - * Scanner API. - * - */ -public interface Scanner { - - TokenType scan(); - - TokenType getTokenType(); - - /** - * Starting offset position of the current token - * - * @return int of token's start offset - */ - int getTokenOffset(); - - int getTokenLength(); - - /** - * Ending offset position of the current token - * - * @return int of token's end offset - */ - int getTokenEnd(); - - String getTokenText(); - - String getTokenError(); - - ScannerState getScannerState(); - - /** - * @return True if the token's Text is empty or all whitespace - */ - boolean isTokenTextBlank(); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/ScannerState.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/ScannerState.java deleted file mode 100644 index d0a804978..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/ScannerState.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - * - Nikolas Komonen - additions for CDATA and Processing Instruction - */ -package org.eclipse.lemminx.dom.parser; - -/** - * XML Scanner state. - * - */ -public enum ScannerState { - WithinContent, AfterOpeningStartTag, AfterOpeningEndTag, WithinProlog, WithinTag, WithinEndTag, - WithinComment, AfterAttributeName, BeforeAttributeValue, WithinCDATA, AfterClosingCDATATag, StartCDATATag, - AfterPrologOpen, PrologOrPI, WithinPI, - - // DTD - DTDWithinDoctype, DTDAfterDoctypeName, DTDAfterDoctypePUBLIC, DTDAfterDoctypeSYSTEM, - DTDAfterDoctypePublicId,DTDWithinContent, DTDWithinElement, DTDWithinAttlist, DTDWithinEntity, - DTDElementAfterName, DTDElementWithinContent, DTDAfterAttlistName, DTDAfterAttlistElementName, - DTDAfterAttlistAttributeName, DTDAfterAttlistAttributeType, DTDAfterEntityName, DTDUnrecognizedParameters, - DTDWithinNotation, DTDAfterNotationName, DTDAfterNotationPUBLIC, DTDAfterNotationSYSTEM, - DTDAfterNotationPublicId, DTDAfterEntityPUBLIC, DTDAfterEntitySYSTEM, DoctypeUnrecognizedParameters; - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/TokenType.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/TokenType.java deleted file mode 100644 index 43ed6e3c3..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/TokenType.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom.parser; - -/** - * XML Token type. - * - */ -public enum TokenType { - - StartCommentTag, - Comment, - EndCommentTag, - CDATATagOpen, - CDATAContent, - CDATATagClose, - StartTagOpen, - StartTagClose, - StartTagSelfClose, - StartTag, - EndTagOpen, - EndTagClose, - EndTag, - DelimiterAssign, - AttributeName, - AttributeValue, - StartPrologOrPI, - PrologName, - PIName, - PIContent, - PIEnd, - PrologEnd, - Content, - Whitespace, - Unknown, - EOS, - // DTD - DTDStartDoctypeTag, - DTDDoctypeName, - DTDDocTypeKindPUBLIC, - DTDDocTypeKindSYSTEM, - DTDDoctypePublicId, - DTDDoctypeSystemId, - DTDEndDoctypeTag, - DTDStartInternalSubset, - DTDEndInternalSubset, - // DTD Element declaration - DTDStartElement, - DTDElementDeclName, - DTDElementCategory, - DTDStartElementContent, - DTDElementContent, - DTDEndElementContent, - - // DTD AttrList declaration - DTDStartAttlist, - DTDAttlistElementName, - DTDAttlistAttributeValue, - DTDAttlistAttributeType, - DTDAttlistAttributeName, - - // DTD Entity - DTDStartEntity, - DTDEntityPercent, - DTDEntityKindPUBLIC, - DTDEntityKindSYSTEM, - DTDEntityPublicId, - DTDEntitySystemId, - DTDEntityName, - DTDEntityValue, - - // DTD Notation - DTDStartNotation, - DTDNotationName, - DTDNotationKindPUBLIC, - DTDNotationKindSYSTEM, - DTDNotationPublicId, - DTDNotationSystemId, - - //For any DTD Decl Tag that has an unrecognized parameter - DTDUnrecognizedParameters, - - //End of any DTD Decl Tag - DTDEndTag; - - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/XMLScanner.java b/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/XMLScanner.java deleted file mode 100644 index 2a305737b..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/dom/parser/XMLScanner.java +++ /dev/null @@ -1,1063 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Initial code from https://github.com/Microsoft/vscode-html-languageservice - * Initial copyright Copyright (C) Microsoft Corporation. All rights reserved. - * Initial license: MIT - * - * Contributors: - * - Microsoft Corporation: Initial code, written in TypeScript, licensed under MIT license - * - Angelo Zerr - translation and adaptation to Java - */ -package org.eclipse.lemminx.dom.parser; - -import static org.eclipse.lemminx.dom.parser.Constants.ATTRIBUTE_NAME_REGEX; -import static org.eclipse.lemminx.dom.parser.Constants.DOCTYPE_KIND_OPTIONS; -import static org.eclipse.lemminx.dom.parser.Constants.DTD_ELEMENT_CATEGORY; -import static org.eclipse.lemminx.dom.parser.Constants.ELEMENT_NAME_REGEX; -import static org.eclipse.lemminx.dom.parser.Constants.PROLOG_NAME_OPTIONS; -import static org.eclipse.lemminx.dom.parser.Constants.URL_VALUE_REGEX; -import static org.eclipse.lemminx.dom.parser.Constants._AST; -import static org.eclipse.lemminx.dom.parser.Constants._AVL; -import static org.eclipse.lemminx.dom.parser.Constants._CAR; -import static org.eclipse.lemminx.dom.parser.Constants._CRB; -import static org.eclipse.lemminx.dom.parser.Constants._CSB; -import static org.eclipse.lemminx.dom.parser.Constants._CVL; -import static org.eclipse.lemminx.dom.parser.Constants._DDT; -import static org.eclipse.lemminx.dom.parser.Constants._DOT; -import static org.eclipse.lemminx.dom.parser.Constants._DQO; -import static org.eclipse.lemminx.dom.parser.Constants._DVL; -import static org.eclipse.lemminx.dom.parser.Constants._EQS; -import static org.eclipse.lemminx.dom.parser.Constants._EVL; -import static org.eclipse.lemminx.dom.parser.Constants._EXL; -import static org.eclipse.lemminx.dom.parser.Constants._FSL; -import static org.eclipse.lemminx.dom.parser.Constants._IVL; -import static org.eclipse.lemminx.dom.parser.Constants._LAN; -import static org.eclipse.lemminx.dom.parser.Constants._LVL; -import static org.eclipse.lemminx.dom.parser.Constants._MIN; -import static org.eclipse.lemminx.dom.parser.Constants._MVL; -import static org.eclipse.lemminx.dom.parser.Constants._NVL; -import static org.eclipse.lemminx.dom.parser.Constants._NWL; -import static org.eclipse.lemminx.dom.parser.Constants._ORB; -import static org.eclipse.lemminx.dom.parser.Constants._OSB; -import static org.eclipse.lemminx.dom.parser.Constants._OVL; -import static org.eclipse.lemminx.dom.parser.Constants._PCT; -import static org.eclipse.lemminx.dom.parser.Constants._PLS; -import static org.eclipse.lemminx.dom.parser.Constants._PVL; -import static org.eclipse.lemminx.dom.parser.Constants._QMA; -import static org.eclipse.lemminx.dom.parser.Constants._RAN; -import static org.eclipse.lemminx.dom.parser.Constants._SIQ; -import static org.eclipse.lemminx.dom.parser.Constants._SVL; -import static org.eclipse.lemminx.dom.parser.Constants._TVL; -import static org.eclipse.lemminx.dom.parser.Constants._UDS; -import static org.eclipse.lemminx.dom.parser.Constants._WSP; -import static org.eclipse.lemminx.dom.parser.Constants._YVL; - -import java.util.function.Predicate; - -import org.eclipse.lemminx.dom.DOMDocumentType.DocumentTypeKind; -import org.eclipse.lemminx.utils.StringUtils;; - -/** - * XML scanner implementation. - * - */ -public class XMLScanner implements Scanner { - - private static final Predicate START_ELEMENT_NAME_PREDICATE = ch -> { - // ^[_:\w] - return ch == _UDS || ch == _DDT || Character.isLetter(ch); - }; - - private static final Predicate ELEMENT_NAME_PREDICATE = ch -> { - // [_:\w-.\d]* - return ch == _UDS /* '_' */ || ch == _DDT /* ':' */ || ch == _DOT /* '.' */ || ch == _MIN /* '-' */ - || Character.isLetterOrDigit(ch); - }; - - private static final Predicate ATTRIBUTE_NAME_PREDICATE = ch -> { - // ^[^\s\?\"'<>\/=\x00-\x0F\x7F\x80-\x9F]* - return !Character.isWhitespace(ch) && ch != _QMA && ch != _DQO && ch != _SIQ && ch != _LAN && ch != _RAN - && ch != _FSL && ch != _EQS && !(ch >= 0x00 && ch <= 0x0F) && ch != 0x7F && !(ch >= 0x80 && ch <= 0x9F); - }; - - MultiLineStream stream; - ScannerState state; - int tokenOffset; - TokenType tokenType; - String tokenError; - - String lastDoctypeKind; - String url; - boolean isInsideDTDContent = false; // Either internal dtd in xml file OR external dtd in dtd file - boolean isDeclCompleted = false; // If any type of DTD declaration was supplied with all the required properties - TokenType tempToken; - boolean isDTDFile; - /** - * boolean completedInitialAttDef; - * - * If the first attribute definition was completed in an ATTLIST declaration - * eg: - * - */ - boolean isInitialAttlistDeclCompleted = false; - private int nbBraceOpened; - - public XMLScanner(String input, int initialOffset, ScannerState initialState, boolean isDTDFile) { - stream = new MultiLineStream(input, initialOffset); - state = initialState; - tokenOffset = 0; - isInsideDTDContent = ScannerState.DTDWithinContent.equals(initialState); - tokenType = TokenType.Unknown; - this.isDTDFile = isDTDFile; - } - - /** - * Returns true if the current token is an element name and false otherwise. - * - * @return true if the current token is an element name and false otherwise. - */ - boolean hasNextElementName() { - // Element name regexp : ^[_:\w][_:\w-.\d]* - // ^[_:\w] - if (!START_ELEMENT_NAME_PREDICATE.test(stream.peekChar())) { - return false; - } - stream.advance(1); - // [_:\w-.\d]* - stream.advanceWhileChar(ELEMENT_NAME_PREDICATE); - return true; - } - - /** - * Returns true if the current token is an attribute name and false otherwise. - * - * @return true if the current token is an attribute name and false otherwise. - */ - boolean hasNextAttributeName() { - // ^[^\s\?\"'<>\/=\x00-\x0F\x7F\x80-\x9F]* - return stream.advanceWhileChar(ATTRIBUTE_NAME_PREDICATE) > 0; - } - - /** - * Returns true if the current token is an attribute value and false otherwise. - * - * @return true if the current token is an attribute value and false otherwise. - */ - boolean hasNextAttributeValue() { - // ^("[^"]*"?)|('[^']*'?) - int first = stream.peekChar(); - if (first == _SIQ || first == _DQO) { - stream.advance(1); - if( stream.advanceUntilChar(first)) { - stream.advance(1); - } - return true; - } - return false; - } - - String doctypeName() { - return stream.advanceIfRegExp(ELEMENT_NAME_REGEX); - } - - /** - * Tries to advance off the regex for either 'PUBLIC' or 'SYSTEM' - * - * @return "PUBLIC" or "SYSTEM" or "" otherwise - */ - String doctypeKind() { - return stream.advanceIfRegExpGroup1(DOCTYPE_KIND_OPTIONS); - } - - TokenType finishToken(int offset, TokenType type) { - return finishToken(offset, type, null); - } - - TokenType finishToken(int offset, TokenType type, String errorMessage) { - tokenType = type; - tokenOffset = offset; - tokenError = errorMessage; - return type; - } - - @Override - public TokenType scan() { - int offset = stream.pos(); - ScannerState oldState = state; - TokenType token = internalScan(); - if (token != TokenType.EOS && offset == stream.pos()) { - log("Scanner.scan has not advanced at offset " + offset + ", state before: " + oldState + " after: " - + state); - stream.advance(1); - return finishToken(offset, TokenType.Unknown); - } - return token; - } - - private void log(String message) { - System.err.println(message); - } - - TokenType internalScan() { - int offset = stream.pos(); - if (stream.eos()) { - return finishToken(offset, TokenType.EOS); - } - String errorMessage = null; - - switch (state) { - case WithinComment: - if (stream.advanceIfChars(_MIN, _MIN, _RAN)) { // --> - state = !isInsideDTDContent ? ScannerState.WithinContent : ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.EndCommentTag); - } - stream.advanceUntilChars(_MIN, _MIN, _RAN); // --> - return finishToken(offset, TokenType.Comment); - - case PrologOrPI: - if (stream.advanceIfChars(_QMA, _RAN)) { // ?> - state = getWithinContentState(); - return finishToken(offset, TokenType.PIEnd); - } - if (stream.advanceUntilAnyOfChars(_NWL, _CAR, _WSP, _QMA, _RAN) || stream.eos()) { // \n or \r or ' ' or '?' - String name = getTokenTextFromOffset(offset); - if (PROLOG_NAME_OPTIONS.matcher(name).matches()) { // name eg: xml - state = ScannerState.WithinTag; - return finishToken(offset, TokenType.PrologName); - } - // if(PI_WITH_VARIABLES.matcher(name).matches()) { // name eg: xml-stylesheet - // state = ScannerState.WithinTag; - // return finishToken(offset, TokenType.PIName); - // } - if (ATTRIBUTE_NAME_REGEX.matcher(name).matches()) { // {name} eg: m2e - state = ScannerState.WithinPI; - return finishToken(offset, TokenType.PIName); - } - } - stream.advanceUntilCharsOrNewTag(_QMA, _RAN); // ?> - if (stream.peekChar() == _LAN) { - state = ScannerState.WithinContent; // TODO: check if EOF causes issues - } - return internalScan(); - - case WithinPI: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChars(_QMA, _RAN)) { - state = getWithinContentState(); - return finishToken(offset, TokenType.PIEnd); - } - if (stream.advanceUntilCharsOrNewTag(_QMA, _RAN)) { // ?> - if (stream.peekChar() == _LAN) { - state = getWithinContentState(); - } - if (getTokenTextFromOffset(offset).length() == 0) { - return finishToken(offset, TokenType.PIEnd); - } - } - return finishToken(offset, TokenType.PIContent); - - case WithinContent: - if (stream.advanceIfChar(_LAN)) { // < - if (!stream.eos() && stream.peekChar() == _EXL) { // ! - if (stream.advanceIfChars(_EXL, _MIN, _MIN)) { // !-- - state = ScannerState.WithinComment; - return finishToken(offset, TokenType.StartCommentTag); - } - if (stream.advanceIfChars(_EXL, _OSB, _CVL, _DVL, _AVL, _TVL, _AVL, _OSB)) { // ![CDATA[ - state = ScannerState.WithinCDATA; - return finishToken(offset, TokenType.CDATATagOpen); - } - - if (stream.advanceIfChars(_EXL, _DVL, _OVL, _CVL, _TVL, _YVL, _PVL, _EVL)) { // !DOCTYPE - isDeclCompleted = false; - state = ScannerState.DTDWithinDoctype; - return finishToken(offset, TokenType.DTDStartDoctypeTag); - } - - } else if (!stream.eos() && stream.advanceIfChar(_QMA)) { // ? - state = ScannerState.PrologOrPI; - return finishToken(offset, TokenType.StartPrologOrPI); - } - if (stream.advanceIfChar(_FSL)) { // / - state = ScannerState.AfterOpeningEndTag; - return finishToken(offset, TokenType.EndTagOpen); - } - state = ScannerState.AfterOpeningStartTag; - return finishToken(offset, TokenType.StartTagOpen); - } - stream.advanceUntilChar(_LAN); // < - return finishToken(offset, TokenType.Content); - - case WithinCDATA: - if (stream.advanceIfChars(_CSB, _CSB, _RAN)) { // ]]> - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.CDATATagClose); - } - stream.advanceUntilChars(_CSB, _CSB, _RAN); // ]]> - return finishToken(offset, TokenType.CDATAContent); - - case AfterOpeningEndTag: - if (hasNextElementName()) { - state = ScannerState.WithinEndTag; - return finishToken(offset, TokenType.EndTag); - } - if (stream.skipWhitespace()) { // white space is not valid here - return finishToken(offset, TokenType.Whitespace, - localize("error.unexpectedWhitespace", "Tag name must directly follow the open bracket.")); - } - state = ScannerState.WithinEndTag; - if (stream.advanceUntilCharOrNewTag(_RAN)) { // > - if (stream.peekChar() == _LAN) { // < - state = ScannerState.WithinContent; - } - return internalScan(); - } - return finishToken(offset, TokenType.Unknown); - - case WithinEndTag: - if (stream.skipWhitespace()) { // white space is valid here - return finishToken(offset, TokenType.Whitespace); - } - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.EndTagClose); - } - if (stream.advanceUntilChar(_LAN)) { // < - state = ScannerState.WithinContent; - return internalScan(); - } - return finishToken(offset, TokenType.Whitespace); - - case AfterOpeningStartTag: - if (hasNextElementName()) { - state = ScannerState.WithinTag; - return finishToken(offset, TokenType.StartTag); - } - if (stream.skipWhitespace()) { // white space is not valid here - return finishToken(offset, TokenType.Whitespace, - localize("error.unexpectedWhitespace", "Tag name must directly follow the open bracket.")); - } - state = ScannerState.WithinTag; - if (stream.advanceUntilCharOrNewTag(_RAN)) { // > - if (stream.peekChar() == _LAN) { // < - state = ScannerState.WithinContent; - } - return internalScan(); - } - return finishToken(offset, TokenType.Unknown); - - case WithinTag: { - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - if (stream.advanceIfChars(_QMA, _RAN)) { // ?> - state = getWithinContentState(); - return finishToken(offset, TokenType.PrologEnd); - } - - if (hasNextAttributeName()) { - state = ScannerState.AfterAttributeName; - return finishToken(offset, TokenType.AttributeName); - } - - if (stream.advanceIfChar(_FSL)) { // / - state = ScannerState.WithinTag; - if(stream.advanceIfChar(_RAN)) { // > - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.StartTagSelfClose); - } - return finishToken(offset, TokenType.Unknown); - } - int c = stream.peekChar(); - if (c == _DQO || c == _SIQ) { // " || ' - state = ScannerState.BeforeAttributeValue; - return internalScan(); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.StartTagClose); - } - - if (stream.advanceUntilChar(_LAN)) { // < - state = ScannerState.WithinContent; - return internalScan(); - } - return finishToken(offset, TokenType.Unknown); - } - case AfterAttributeName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_EQS)) { // = - state = ScannerState.BeforeAttributeValue; - return finishToken(offset, TokenType.DelimiterAssign); - } - state = ScannerState.WithinTag; - return internalScan(); // no advance yet - jump to WithinTag - - case BeforeAttributeValue: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - if (hasNextAttributeValue()) { - state = ScannerState.WithinTag; - return finishToken(offset, TokenType.AttributeValue); - } - state = ScannerState.WithinTag; - return internalScan(); - - // DTD - - case DTDWithinDoctype: - // Possible formats: - // https://en.wikipedia.org/wiki/Document_type_declaration#Syntax - - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_OSB)) { // [ - state = ScannerState.DTDWithinContent; - isInsideDTDContent = true; - return finishToken(offset, TokenType.DTDStartInternalSubset); - } - - if (stream.advanceIfChar(_CSB)) { // ] - state = ScannerState.DTDWithinDoctype; - isInsideDTDContent = false; - isDeclCompleted = true; - return finishToken(offset, TokenType.DTDEndInternalSubset); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.DTDEndDoctypeTag); - } - - if(stream.peekChar() == _LAN) { // < - state = ScannerState.WithinContent; - return internalScan(); - } - - - if (isDeclCompleted == false) { - String doctypeName = doctypeName(); - if(!doctypeName.equals("")) { - state = ScannerState.DTDAfterDoctypeName; - return finishToken(offset, TokenType.DTDDoctypeName); - } - } - stream.advanceUntilCharOrNewTag(_RAN); // > || < - return finishToken(offset, TokenType.DTDUnrecognizedParameters); - - case DTDAfterDoctypeName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - if (stream.advanceIfChar(_OSB)) { // [ - state = ScannerState.DTDWithinContent; - isInsideDTDContent = true; - return finishToken(offset, TokenType.DTDStartInternalSubset); - } - lastDoctypeKind = doctypeKind(); // eg: PUBLIC || SYSTEM - if (lastDoctypeKind.equals(DocumentTypeKind.PUBLIC.name())) { - state = ScannerState.DTDAfterDoctypePUBLIC; - return finishToken(offset, TokenType.DTDDocTypeKindPUBLIC); - } else if (lastDoctypeKind.equals(DocumentTypeKind.SYSTEM.name())) { - state = ScannerState.DTDAfterDoctypeSYSTEM; - return finishToken(offset, TokenType.DTDDocTypeKindSYSTEM); - } - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterDoctypePUBLIC: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - url = stream.advanceIfRegExp(URL_VALUE_REGEX); - if (!url.equals("")) { - state = ScannerState.DTDAfterDoctypePublicId; - return finishToken(offset, TokenType.DTDDoctypePublicId); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterDoctypeSYSTEM: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - state = ScannerState.DTDWithinDoctype; - url = stream.advanceIfRegExp(URL_VALUE_REGEX); - if (!url.equals("")) { - return finishToken(offset, TokenType.DTDDoctypeSystemId); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterDoctypePublicId: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - state = ScannerState.DTDWithinDoctype; - url = stream.advanceIfRegExp(URL_VALUE_REGEX); // scan the System Identifier URL - if (!url.equals("")) { - return finishToken(offset, TokenType.DTDDoctypeSystemId); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDWithinContent: - if (!isDTDFile && (stream.advanceIfChar(_CSB) || stream.peekChar() == _RAN)) { // ] || > - state = ScannerState.DTDWithinDoctype; - isInsideDTDContent = false; - return finishToken(offset, TokenType.DTDEndInternalSubset); - } - boolean startsWithLessThanBracket = false; - if (stream.advanceIfChar(_LAN)) { // < - startsWithLessThanBracket = true; - if (!stream.eos() && stream.peekChar() == _EXL) { // ! - isDeclCompleted = false; - if (stream.advanceIfChars(_EXL, _EVL, _LVL, _EVL, _MVL, _EVL, _NVL, _TVL)) { // !ELEMENT - state = ScannerState.DTDWithinElement; - return finishToken(offset, TokenType.DTDStartElement); - } else if (stream.advanceIfChars(_EXL, _AVL, _TVL, _TVL, _LVL, _IVL, _SVL, _TVL)) { // !ATTLIST - isInitialAttlistDeclCompleted = false; - state = ScannerState.DTDWithinAttlist; - return finishToken(offset, TokenType.DTDStartAttlist); - } else if (stream.advanceIfChars(_EXL, _EVL, _NVL, _TVL, _IVL, _TVL, _YVL)) { // !ENTITY - state = ScannerState.DTDWithinEntity; - return finishToken(offset, TokenType.DTDStartEntity); - } else if (stream.advanceIfChars(_EXL, _NVL, _OVL, _TVL, _AVL, _TVL, _IVL, _OVL, _NVL)) { // !NOTATION - state = ScannerState.DTDWithinNotation; - return finishToken(offset, TokenType.DTDStartNotation); - } else if (stream.advanceIfChars(_EXL, _MIN, _MIN)) { // !-- (for comment) - state = ScannerState.WithinComment; - return finishToken(offset, TokenType.StartCommentTag); - } - } - } - if(isDTDFile) { - if(startsWithLessThanBracket) { - if (stream.advanceIfChar(_QMA)) { // ? - state = ScannerState.PrologOrPI; - return finishToken(offset, TokenType.StartPrologOrPI); - } - if(stream.advanceUntilCharOrNewTag(_RAN)){ // > - if(stream.peekChar() == _RAN) { - stream.advance(1); //consume '>' - } - } - } - else { - stream.advanceUntilAnyOfChars(_LAN); // < - } - } else { - stream.advanceUntilAnyOfChars(_RAN, _LAN, _CSB); // > || < || ] - if(startsWithLessThanBracket && stream.peekChar() == _RAN) { - stream.advance(1); //consume '>' - } - } - return finishToken(offset, TokenType.Content); - - - - case DTDUnrecognizedParameters: - - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if(stream.advanceIfChar(_RAN)) { // > - state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; - tempToken = isInsideDTDContent ? TokenType.DTDEndTag : TokenType.EndTagClose; - return finishToken(offset, tempToken); - } - - if(stream.peekChar() == _LAN) { // < - state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; - return internalScan(); - } - - if(stream.peekChar() == _CSB && isInsideDTDContent) { // ] - state = ScannerState.DTDWithinDoctype; - return internalScan(); - } - - //If in DOCTYPE this will skip over the whole internal subset - if(!isInsideDTDContent) { - stream.advanceUntilAnyOfChars(_OSB, _RAN, _LAN); // [ | < | > - if(stream.peekChar() == _OSB) { - stream.advance(1); - stream.advanceUntilCharUsingStack(_CSB);// ] - - } - } - - if(stream.advanceUntilCharOrNewTag(_RAN)) { // > - if(stream.peekChar() == _LAN) { // < - state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.DTDWithinDoctype; - } - } - return finishToken(offset, TokenType.DTDUnrecognizedParameters); - - - case DTDWithinElement: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - if(isDeclCompleted == true) { - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - } - - if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDElementAfterName; - return finishToken(offset, TokenType.DTDElementDeclName); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDElementAfterName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_ORB)) { // ( - nbBraceOpened = 1; - state = ScannerState.DTDElementWithinContent; - return finishToken(offset, TokenType.DTDStartElementContent); - } - - if (!stream.advanceIfRegExpGroup1(DTD_ELEMENT_CATEGORY).equals("")) { - isDeclCompleted = true; - state = ScannerState.DTDWithinElement; - return finishToken(offset, TokenType.DTDElementCategory); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDElementWithinContent: // - - if(stream.advanceIfChar(_CRB)) { // ) - isDeclCompleted = true; - state = ScannerState.DTDWithinElement; - stream.advanceIfAnyOfChars(_QMA, _AST, _PLS); // ? | * | + - return finishToken(offset, TokenType.DTDEndElementContent); - } - - while(nbBraceOpened > 0) { - int c = stream.peekChar(); - - if(c == _ORB) { // ( - nbBraceOpened++; - } - else if(c == _CRB) { // ) - nbBraceOpened--; - if(nbBraceOpened == 0) { - return finishToken(offset, TokenType.DTDElementContent); - } - } - else if(c == _RAN) { // > - state = ScannerState.DTDWithinElement; - return finishToken(offset, TokenType.DTDElementContent); - } - else if(c == _LAN) { // < - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDElementContent); - } - else if(c == -1) { - return finishToken(offset, TokenType.DTDElementContent); - } - stream.advance(1); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDWithinAttlist: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - if(isDeclCompleted == true) { - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - } - - if (isInitialAttlistDeclCompleted == false && !stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterAttlistElementName; - return finishToken(offset, TokenType.DTDAttlistElementName); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterAttlistElementName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExp(Constants.ATTRIBUTE_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterAttlistAttributeName; - return finishToken(offset, TokenType.DTDAttlistAttributeName); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterAttlistAttributeName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExpGroup1(Constants.DTD_ATTLIST_ATTRIBUTE_TYPE).equals("")) { - state = ScannerState.DTDAfterAttlistAttributeType; - return finishToken(offset, TokenType.DTDAttlistAttributeType); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterAttlistAttributeType: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExpGroup1(Constants.DTD_ATTLIST_ATTRIBUTE_VALUE).equals("")) { - isInitialAttlistDeclCompleted = true; //we completed the initial attribute declaration - isDeclCompleted = true; - state = ScannerState.DTDAfterAttlistElementName; - return finishToken(offset, TokenType.DTDAttlistAttributeValue); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDWithinEntity: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - if(isDeclCompleted == true) { - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - } - - if (!stream.advanceIfRegExp(Constants.ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterEntityName; - return finishToken(offset, TokenType.DTDEntityName); - } - - if (stream.advanceIfChar(_PCT)) { // % - return finishToken(offset, TokenType.DTDEntityPercent); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterEntityName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExp(Constants.DTD_ENTITY_VALUE).equals("")) { - isDeclCompleted = true; - state = ScannerState.DTDWithinEntity; - return finishToken(offset, TokenType.DTDEntityValue); - } - - lastDoctypeKind = doctypeKind(); // eg: PUBLIC || SYSTEM, will advance the stream if either of these - if (lastDoctypeKind.equals(DocumentTypeKind.PUBLIC.name())) { - state = ScannerState.DTDAfterEntityPUBLIC; - return finishToken(offset, TokenType.DTDEntityKindPUBLIC); - } else if (lastDoctypeKind.equals(DocumentTypeKind.SYSTEM.name())) { - state = ScannerState.DTDAfterEntitySYSTEM; - return finishToken(offset, TokenType.DTDEntityKindSYSTEM); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterEntityPUBLIC: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExp(URL_VALUE_REGEX).equals("")) { - state = ScannerState.DTDAfterEntitySYSTEM; - return finishToken(offset, TokenType.DTDEntityPublicId); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterEntitySYSTEM: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if (!stream.advanceIfRegExp(URL_VALUE_REGEX).equals("")) { - isDeclCompleted = true; - state = ScannerState.DTDWithinEntity; - return finishToken(offset, TokenType.DTDEntitySystemId); - } - - if (stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDWithinNotation: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - if(stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); - } - - if(isDeclCompleted == true) { - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - } - - if (!stream.advanceIfRegExp(ELEMENT_NAME_REGEX).equals("")) { - state = ScannerState.DTDAfterNotationName; - return finishToken(offset, TokenType.DTDNotationName); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterNotationName: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - lastDoctypeKind = doctypeKind(); // eg: PUBLIC || SYSTEM, will advance the stream if either of these - if (lastDoctypeKind.equals(DocumentTypeKind.PUBLIC.name())) { - state = ScannerState.DTDAfterNotationPUBLIC; - return finishToken(offset, TokenType.DTDNotationKindPUBLIC); - } else if (lastDoctypeKind.equals(DocumentTypeKind.SYSTEM.name())) { - state = ScannerState.DTDAfterNotationSYSTEM; - return finishToken(offset, TokenType.DTDNotationKindSYSTEM); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterNotationPUBLIC: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - url = stream.advanceIfRegExp(URL_VALUE_REGEX); - if (!url.equals("")) { - isDeclCompleted = true; - state = ScannerState.DTDAfterNotationPublicId; - return finishToken(offset, TokenType.DTDNotationPublicId); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterNotationSYSTEM: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - state = ScannerState.DTDWithinNotation; - url = stream.advanceIfRegExp(URL_VALUE_REGEX); - if (!url.equals("")) { - isDeclCompleted = true; - state = ScannerState.DTDAfterNotationName; - return finishToken(offset, TokenType.DTDNotationSystemId); - } - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - case DTDAfterNotationPublicId: - if (stream.skipWhitespace()) { - return finishToken(offset, TokenType.Whitespace); - } - - state = ScannerState.DTDAfterNotationName; - url = stream.advanceIfRegExp(URL_VALUE_REGEX); // scan the System Identifier URL - if (!url.equals("")) { - isDeclCompleted = true; - return finishToken(offset, TokenType.DTDNotationSystemId); - } - - state = ScannerState.DTDUnrecognizedParameters; - return internalScan(); - - default: - } - - - stream.advance(1); - state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; - return finishToken(offset, TokenType.Unknown, errorMessage); - } - - private String localize(String string, String string2) { - return string; - } - - private ScannerState getWithinContentState() { - if (isDTDFile) { - return ScannerState.DTDWithinContent; - } - return ScannerState.WithinContent; - } - - public int getLastNonWhitespaceOffset() { - return stream.getLastNonWhitespaceOffset(); - } - - @Override - public TokenType getTokenType() { - return tokenType; - } - - @Override - /** - * Starting offset position of the current token - * - * @return Starting offset position of the current token - */ - public int getTokenOffset() { - return tokenOffset; - } - - @Override - public int getTokenLength() { - return stream.pos() - tokenOffset; - } - - @Override - /** - * Ending offset position of the current token - * - * @return Ending offset position of the current token - */ - public int getTokenEnd() { - return stream.pos(); - } - - @Override - public String getTokenText() { - return stream.getSource().substring(tokenOffset, stream.pos()); - } - - @Override - public boolean isTokenTextBlank() { - return StringUtils.isWhitespace(stream.getSource(), tokenOffset, stream.pos()); - } - - @Override - public ScannerState getScannerState() { - return state; - } - - @Override - public String getTokenError() { - return tokenError; - } - - public String getTokenTextFromOffset(int offset) { - return stream.getSource().substring(offset, stream.pos()); - } - - public static Scanner createScanner(String input) { - return createScanner(input, false); - } - - public static Scanner createScanner(String input, boolean isDTD) { - return createScanner(input, 0, isDTD); - } - - public static Scanner createScanner(String input, int initialOffset) { - return createScanner(input, initialOffset, false); - } - - public static Scanner createScanner(String input, int initialOffset, boolean isDTDFile) { - return createScanner(input, initialOffset, - isDTDFile ? ScannerState.DTDWithinContent : ScannerState.WithinContent, isDTDFile); - } - - public static Scanner createScanner(String input, int initialOffset, ScannerState initialState) { - return new XMLScanner(input, initialOffset, initialState, false); - } - - public static Scanner createScanner(String input, int initialOffset, ScannerState initialState, boolean isDTDFile) { - return new XMLScanner(input, initialOffset, initialState, isDTDFile); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogCatalogEntry.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogCatalogEntry.java deleted file mode 100644 index b8de9afa3..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogCatalogEntry.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.catalog; - -import java.nio.file.Paths; - -import org.eclipse.lemminx.dom.DOMAttr; -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.dom.DOMRange; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; - -/** - * Represents a catalog entry that uses the "catalog" attribute to reference an external document - */ -public class CatalogCatalogEntry extends CatalogEntry { - - public CatalogCatalogEntry(@NonNull String baseURI, DOMElement entryElement) { - super(baseURI, entryElement); - } - - @Override - public DOMRange getLinkRange() { - DOMAttr catalogAttr = CatalogUtils.getCatalogEntryCatalog(getEntryElement()); - if (catalogAttr == null) { - return null; - } - return catalogAttr.getNodeAttrValue(); - } - - @Override - public String getResolvedURI() { - DOMAttr catalogAttr = CatalogUtils.getCatalogEntryCatalog(getEntryElement()); - if (catalogAttr == null) { - return null; - } - String lastSegment = catalogAttr.getValue(); - if (StringUtils.isBlank(lastSegment)) { - return null; - } - return Paths.get(getBaseURI(), lastSegment).toString(); - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogEntry.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogEntry.java deleted file mode 100644 index 1bc737072..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogEntry.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.catalog; - -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.dom.DOMRange; - -/** - * Represents a catalog entry that references an external document - */ -public abstract class CatalogEntry { - - private final String baseURI; - private final DOMElement entryElement; - - /** - * - * @param baseURI 's xml:base + 's xml:base (if in a - * ) - * @param entryElement the element that corresponds with this catalog entry - */ - protected CatalogEntry(String baseURI, DOMElement entryElement) { - this.baseURI = baseURI; - this.entryElement = entryElement; - } - - /** - * Returns the base URI for this catalog entry - * - * @return the base URI for this catalog entry - */ - public String getBaseURI() { - return baseURI; - } - - /** - * Returns the element that corresponds with this catalog entry - * - * @return the element that corresponds with this catalog entry - */ - protected DOMElement getEntryElement() { - return entryElement; - } - - /** - * Returns the range in the document where the link to an external document is, - * or null if this catalog entry does not refer to an external document - * - * @return the range in the document where the link to an external document is - */ - public abstract DOMRange getLinkRange(); - - /** - * Returns the URI for the document that this catalog entry references, or null - * if this catalog entry does not refer to an external document - * - * @return the URI for the document that this catalog entry references - */ - public abstract String getResolvedURI(); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java deleted file mode 100644 index 73c23bb5e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java +++ /dev/null @@ -1,198 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ - -package org.eclipse.lemminx.extensions.catalog; - -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.eclipse.lemminx.dom.DOMAttr; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.dom.DOMNode; -import org.eclipse.lemminx.utils.DOMUtils; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; - -/** - * Utility functions for working with XML catalog documents - */ -public class CatalogUtils { - - /** - * The catalog entries that have a 'uri' attribute - */ - private static final Collection HAS_URI_ATTRIBUTE = Arrays.asList("public", "system", "uri", "systemSuffix", - "uriSuffix"); - - /** - * The catalog entries that have a 'catalog' attribute - */ - private static final Collection HAS_CATALOG_ATTRIBUTE = Arrays.asList("delegatePublic", "delegateSystem", - "delegateUri", "nextCatalog"); - - private static final String XML_BASE_ATTRIBUTE = "xml:base"; - - private static final String CATALOG_ENTITY_NAME = "catalog"; - - private static final String GROUP_ENTITY_NAME = "group"; - - private static final String URI_ATTRIBUTE_NAME = "uri"; - - private static final String CATALOG_ATTRIBUTE_NAME = "catalog"; - - /** - * Returns a list of all the catalog entries in the given document, or an empty - * list if the document is not a catalog. - * - * @return a list of all the catalog entries in the given document, or an empty - * list if the document is not a catalog. - */ - public static List getCatalogEntries(DOMDocument document) { - if (!DOMUtils.isCatalog(document)) { - return Collections.emptyList(); - } - for (DOMNode n : document.getChildren()) { - if (n.isElement() && CATALOG_ENTITY_NAME.equals(n.getNodeName())) { - return collectCatalogEntries((DOMElement) n); - } - } - return Collections.emptyList(); - } - - /** - * Returns the uri attribute node of the given catalog entry or null if there is - * no uri attribute - * - * @param element The catalog entry to get the uri attribute of - * @return the uri attribute node of the given catalog entry or null if there is - * no uri attribute - */ - public static DOMAttr getCatalogEntryURI(DOMElement element) { - return element.getAttributeNode(URI_ATTRIBUTE_NAME); - } - - /** - * Returns the catalog attribute node of the given catalog entry or null if - * there is no catalog attribute - * - * @param element The catalog entry to get the catalog attribute of - * @return the catalog attribute node of the given catalog entry or null if - * there is no catalog attribute - */ - public static DOMAttr getCatalogEntryCatalog(DOMElement element) { - return element.getAttributeNode(CATALOG_ATTRIBUTE_NAME); - } - - /** - * Returns true if this element is a catalog entry that is required to have the - * 'uri' attribute and false otherwise - * - * @param element The element to check - * @return true if this element is an catalog entry that is required to have the - * 'uri' attribute and false otherwise - */ - private static boolean isCatalogEntryWithURI(DOMElement element) { - return HAS_URI_ATTRIBUTE.contains(element.getNodeName()); - } - - /** - * Returns true if this element is a catalog entry that is required to have the - * 'catalog' attribute and false otherwise - * - * @param element The element to check - * @return true if this element is an catalog entry that is required to have the - * 'catalog' attribute and false otherwise - */ - private static boolean isCatalogEntryWithCatalog(DOMElement element) { - return HAS_CATALOG_ATTRIBUTE.contains(element.getNodeName()); - } - - /** - * Returns true if the given element is a group element and false otherwise - * - * @param element The element to check - * @return true if the given element is a group element and false otherwise - */ - private static boolean isGroupCatalogEntry(DOMElement element) { - return GROUP_ENTITY_NAME.equals(element.getNodeName()); - } - - /** - * Get a list of all catalog entry elements that are in the given catalog - * - * @param catalog the catalog element to collect the entries for - * @return A list of all the catalog entities in this catalog - */ - private static List collectCatalogEntries(@NonNull DOMElement catalog) { - List entries = new ArrayList<>(); - String baseURI = catalog.getAttribute(XML_BASE_ATTRIBUTE); - baseURI = baseURI == null ? "" : baseURI; - for (DOMNode node : catalog.getChildren()) { - if (node.isElement()) { - DOMElement element = (DOMElement) node; - CatalogEntry catalogEntry = createCatalogEntry(baseURI, element); - if (catalogEntry != null) { - entries.add(catalogEntry); - } else if (isGroupCatalogEntry(element)) { - entries.addAll(collectGroupEntries(element, baseURI)); - } - } - } - return entries; - } - - /** - * Get a list of all catalog entry elements that are in the given group - * - * @param group the group element to collect the entries for - * @param baseURI the baseURI of the catalog - * @return A list of all the catalog entities in this group - */ - private static List collectGroupEntries(DOMElement group, @NonNull String baseURI) { - List entries = new ArrayList<>(); - String groupSegment = group.getAttribute(XML_BASE_ATTRIBUTE); - if (groupSegment != null) { - baseURI = Paths.get(baseURI, groupSegment).toString(); - } - for (DOMNode node : group.getChildren()) { - if (node.isElement()) { - DOMElement element = (DOMElement) node; - CatalogEntry catalogEntry = createCatalogEntry(baseURI, element); - if (catalogEntry != null) { - entries.add(catalogEntry); - } - } - } - return entries; - } - - /** - * Returns a catalog entry for the given element and null if a catalog entry - * can't be made - * - * @param baseURI the base URI of the catalog entry - * @param element the element to turn into a catalog entry - * @return a catalog entry for the given element and null if a catalog entry - * can't be made - */ - private static CatalogEntry createCatalogEntry(@NonNull String baseURI, DOMElement element) { - if (isCatalogEntryWithURI(element)) { - return new URICatalogEntry(baseURI, element); - } else if (isCatalogEntryWithCatalog(element)) { - return new CatalogCatalogEntry(baseURI, element); - } - return null; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/URICatalogEntry.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/URICatalogEntry.java deleted file mode 100644 index ae699318d..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/URICatalogEntry.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.catalog; - -import java.nio.file.InvalidPathException; -import java.nio.file.Paths; - -import org.eclipse.lemminx.dom.DOMAttr; -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.dom.DOMRange; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; - -/** - * Represents a catalog entry that uses the "uri" attribute to reference an external document - */ -public class URICatalogEntry extends CatalogEntry { - - public URICatalogEntry(@NonNull String baseURI, DOMElement entryElement) { - super(baseURI, entryElement); - } - - @Override - public DOMRange getLinkRange() { - DOMAttr uriAttr = CatalogUtils.getCatalogEntryURI(getEntryElement()); - if (uriAttr == null) { - return null; - } - return uriAttr.getNodeAttrValue(); - } - - @Override - public String getResolvedURI() { - DOMAttr uriAttr = CatalogUtils.getCatalogEntryURI(getEntryElement()); - if (uriAttr == null) { - return null; - } - String lastSegment = uriAttr.getValue(); - if (StringUtils.isBlank(lastSegment)) { - return null; - } - try { - return Paths.get(getBaseURI(), lastSegment).toString(); - } catch (InvalidPathException e) { - // See issue #977 - return null; - } - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java deleted file mode 100644 index 217ccc431..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ - -package org.eclipse.lemminx.extensions.catalog; - -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.apache.xerces.impl.XMLEntityManager; -import org.apache.xerces.util.URI.MalformedURIException; -import org.eclipse.lemminx.commons.BadLocationException; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lemminx.utils.XMLPositionUtility; -import org.eclipse.lsp4j.DocumentLink; - -/** - * Document links that are specific to catalogs - */ -public class XMLCatalogDocumentLinkParticipant implements IDocumentLinkParticipant { - - private static Logger LOGGER = Logger.getLogger(XMLCatalogDocumentLinkParticipant.class.getName()); - - @Override - public void findDocumentLinks(DOMDocument document, List links) { - for (CatalogEntry catalogEntry : CatalogUtils.getCatalogEntries(document)) { - DocumentLink docLink = createDocumentLinkFromCatalogEntry(document, catalogEntry); - if (docLink != null) { - links.add(docLink); - } - } - } - - /** - * Return a DocumentLink for the given CatalogEntry or null if this fails - * - * @param document The document that the attribute belongs to - * @param catalogEntry The CatalogEntry that should be turned into a - * DocumentLink - * @return a document link that links the CatalogEntry to the external document - * it references or null otherwise - */ - private static DocumentLink createDocumentLinkFromCatalogEntry(DOMDocument document, CatalogEntry catalogEntry) { - try { - String path = getResolvedLocation(FilesUtils.removeFileScheme(document.getDocumentURI()), - catalogEntry.getResolvedURI()); - if (path != null && catalogEntry.getLinkRange() != null) { - return XMLPositionUtility.createDocumentLink(catalogEntry.getLinkRange(), path, true); - } - } catch (BadLocationException e) { - LOGGER.log(Level.SEVERE, "Creation of document link failed", e); - } - return null; - } - - /** - * Returns the expanded system location - * - * @return the expanded system location - */ - private static String getResolvedLocation(String documentURI, String location) { - if (StringUtils.isBlank(location)) { - return null; - } - try { - return XMLEntityManager.expandSystemId(location, documentURI, false); - } catch (MalformedURIException e) { - return location; - } - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java deleted file mode 100644 index 6455cf0b3..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.catalog; - -import java.nio.file.Files; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.lemminx.client.InvalidPathWarner; -import org.eclipse.lemminx.client.PathFeature; -import org.eclipse.lemminx.extensions.contentmodel.settings.ContentModelSettings; -import org.eclipse.lemminx.services.IXMLNotificationService; -import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; -import org.eclipse.lemminx.services.extensions.IXMLExtension; -import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; -import org.eclipse.lemminx.services.extensions.save.ISaveContext; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lsp4j.InitializeParams; - -/** - * XMl Catalog plugin. - */ -public class XMLCatalogPlugin implements IXMLExtension { - - private XMLCatalogURIResolverExtension uiResolver; - private final IDocumentLinkParticipant documentLinkParticipant; - - private InvalidPathWarner pathWarner; - - public XMLCatalogPlugin() { - documentLinkParticipant = new XMLCatalogDocumentLinkParticipant(); - } - - @Override - public void doSave(ISaveContext context) { - Object initializationOptionsSettings = context.getSettings(); - ContentModelSettings cmSettings = ContentModelSettings.getContentModelXMLSettings(initializationOptionsSettings); - if (cmSettings == null) { - return; - } - validateCatalogPaths(cmSettings); - } - - @Override - public void start(InitializeParams params, XMLExtensionsRegistry registry) { - uiResolver = new XMLCatalogURIResolverExtension(registry); - registry.getResolverExtensionManager().registerResolver(uiResolver); - IXMLNotificationService notificationService = registry.getNotificationService(); - if (notificationService != null) { - this.pathWarner = new InvalidPathWarner(notificationService); - } - registry.registerDocumentLinkParticipant(documentLinkParticipant); - } - - @Override - public void stop(XMLExtensionsRegistry registry) { - registry.getResolverExtensionManager().unregisterResolver(uiResolver); - } - - private void validateCatalogPaths(ContentModelSettings cmSettings) { - if (this.pathWarner == null) { - return; // happen when notification service is not available - } - String[] catalogs = cmSettings.getCatalogs(); - Set invalidCatalogs = Arrays.stream(catalogs).filter(c -> { - return Files.notExists(FilesUtils.getPath(c)); - }).collect(Collectors.toSet()); - - if (invalidCatalogs.size() > 0) { - this.pathWarner.onInvalidFilePath(invalidCatalogs, PathFeature.CATALOGS); - } else { - this.pathWarner.evictKey(PathFeature.CATALOGS); - } - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogURIResolverExtension.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogURIResolverExtension.java deleted file mode 100644 index 88961a4b9..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogURIResolverExtension.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.catalog; - -import java.io.IOException; - -import org.apache.xerces.xni.XMLResourceIdentifier; -import org.apache.xerces.xni.XNIException; -import org.apache.xerces.xni.parser.XMLInputSource; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; -import org.eclipse.lemminx.uriresolver.CacheResourcesManager; -import org.eclipse.lemminx.uriresolver.CacheResourcesManager.ResourceToDeploy; -import org.eclipse.lemminx.uriresolver.URIResolverExtension; - -/** - * Resolve the XML Schema of XML/Catalog - * - */ -public class XMLCatalogURIResolverExtension implements URIResolverExtension { - - /** - * The XML Catalog namespace URI (= - * http://www.oasis-open.org/committees/entity/release/1.1/catalog.xsd) - */ - private static final String CATALOG_NAMESPACE_URI = "urn:oasis:names:tc:entity:xmlns:xml:catalog"; //$NON-NLS-1$ - - private static final String CATALOG_SYSTEM = "http://www.oasis-open.org/committees/entity/release/1.1/catalog.xsd"; - - private static final ResourceToDeploy CATALOG_RESOURCE = new ResourceToDeploy(CATALOG_SYSTEM, - "schemas/catalog/catalog-1.1.xsd"); - private final XMLExtensionsRegistry extensionsRegistry; - - @Override - public String getName() { - return "embedded catalog.xsd"; - } - - public XMLCatalogURIResolverExtension(XMLExtensionsRegistry extensionsRegistry) { - this.extensionsRegistry = extensionsRegistry; - } - - @Override - public String resolve(String baseLocation, String publicId, String systemId) { - if (!CATALOG_NAMESPACE_URI.equals(publicId)) { - return null; - } - if (hasDTDorXMLSchema(baseLocation)) { - return null; - } - try { - return CacheResourcesManager.getResourceCachePath(CATALOG_RESOURCE).toFile().toURI().toString(); - } catch (Exception e) { - // Do nothing? - } - return CATALOG_SYSTEM; - } - - @Override - public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) throws XNIException, IOException { - if (hasDTDorXMLSchema(resourceIdentifier.getBaseSystemId())) { - return null; - } - String publicId = resourceIdentifier.getNamespace(); - if (CATALOG_NAMESPACE_URI.equals(publicId)) { - String baseLocation = resourceIdentifier.getBaseSystemId(); - String catalogFilePath = resolve(baseLocation, publicId, null); - if (catalogFilePath != null) { - return new XMLInputSource(publicId, catalogFilePath, catalogFilePath); - } - } - return null; - } - - private boolean hasDTDorXMLSchema(String uri) { - DOMDocument document = extensionsRegistry.getDocumentProvider().getDocument(uri); - if (document == null) { - return false; - } - return document.hasDTD() || document.hasSchemaLocation() || document.hasNoNamespaceSchemaLocation(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/ContentModelPlugin.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/ContentModelPlugin.java deleted file mode 100644 index e1bf8336a..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/ContentModelPlugin.java +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.contentmodel; - -import java.util.Objects; - -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.extensions.contentmodel.commands.AssociateGrammarCommand; -import org.eclipse.lemminx.extensions.contentmodel.commands.CheckBoundGrammarCommand; -import org.eclipse.lemminx.extensions.contentmodel.commands.CheckFilePatternCommand; -import org.eclipse.lemminx.extensions.contentmodel.commands.XMLValidationAllFilesCommand; -import org.eclipse.lemminx.extensions.contentmodel.commands.XMLValidationFileCommand; -import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelCodeActionParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelCodeLensParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelCompletionParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelDocumentLinkParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelHoverParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelSymbolsProviderParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.ContentModelTypeDefinitionParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.DocumentTelemetryParticipant; -import org.eclipse.lemminx.extensions.contentmodel.participants.diagnostics.ContentModelDiagnosticsParticipant; -import org.eclipse.lemminx.extensions.contentmodel.settings.ContentModelSettings; -import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.IXMLValidationService; -import org.eclipse.lemminx.services.extensions.ICodeActionParticipant; -import org.eclipse.lemminx.services.extensions.ICompletionParticipant; -import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; -import org.eclipse.lemminx.services.extensions.IHoverParticipant; -import org.eclipse.lemminx.services.extensions.ITypeDefinitionParticipant; -import org.eclipse.lemminx.services.extensions.IXMLExtension; -import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; -import org.eclipse.lemminx.services.extensions.codelens.ICodeLensParticipant; -import org.eclipse.lemminx.services.extensions.commands.IXMLCommandService; -import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant; -import org.eclipse.lemminx.services.extensions.save.ISaveContext; -import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager; -import org.eclipse.lemminx.utils.DOMUtils; -import org.eclipse.lsp4j.InitializeParams; - -/** - * Content model plugin extension to provide: - * - *
    - *
  • completion based on XML Schema, DTD...
  • - *
  • hover based on XML Schema
  • - *
  • diagnostics based on on XML Schema, DTD...
  • - *
- */ -public class ContentModelPlugin implements IXMLExtension { - - private final ICompletionParticipant completionParticipant; - - private final IHoverParticipant hoverParticipant; - - private final IDiagnosticsParticipant diagnosticsParticipant; - - private final ICodeActionParticipant codeActionParticipant; - - private IDocumentLinkParticipant documentLinkParticipant; - - private final ITypeDefinitionParticipant typeDefinitionParticipant; - - private ContentModelSymbolsProviderParticipant symbolsProviderParticipant; - - private ICodeLensParticipant codeLensParticipant; - - ContentModelManager contentModelManager; - - private ContentModelSettings cmSettings; - - private XMLValidationSettings currentValidationSettings; - - private DocumentTelemetryParticipant documentTelemetryParticipant; - - public ContentModelPlugin() { - completionParticipant = new ContentModelCompletionParticipant(); - hoverParticipant = new ContentModelHoverParticipant(); - diagnosticsParticipant = new ContentModelDiagnosticsParticipant(this); - codeActionParticipant = new ContentModelCodeActionParticipant(); - typeDefinitionParticipant = new ContentModelTypeDefinitionParticipant(); - } - - @Override - public void doSave(ISaveContext context) { - if (context.getType() == ISaveContext.SaveContextType.DOCUMENT) { - // The save is done for a given XML file - String documentURI = context.getUri(); - DOMDocument document = context.getDocument(documentURI); - if (document != null && DOMUtils.isCatalog(document)) { - // the XML document which has changed is a XML catalog. - // 1) refresh catalogs - contentModelManager.refreshCatalogs(); - } - // 2) Validate all opened XML files except the catalog which have changed - context.collectDocumentToValidate(d -> { - DOMDocument xml = context.getDocument(d.getDocumentURI()); - xml.resetGrammar(); - return !documentURI.equals(d.getDocumentURI()); - }); - } else { - // Settings - updateSettings(context); - } - } - - private void updateSettings(ISaveContext saveContext) { - Object initializationOptionsSettings = saveContext.getSettings(); - cmSettings = ContentModelSettings.getContentModelXMLSettings(initializationOptionsSettings); - if (cmSettings != null) { - updateSettings(cmSettings, saveContext); - } else { - currentValidationSettings = null; - } - } - - private void updateSettings(ContentModelSettings settings, ISaveContext context) { - if (settings.getCatalogs() != null) { - // Update XML catalog settings - boolean catalogPathsChanged = contentModelManager.setCatalogs(settings.getCatalogs()); - if (catalogPathsChanged) { - // Validate all opened XML files - context.collectDocumentToValidate(d -> { - DOMDocument xml = context.getDocument(d.getDocumentURI()); - if (xml == null) { - return false; - } - xml.resetGrammar(); - return true; - }); - } - } - if (settings.getFileAssociations() != null) { - // Update XML file associations - boolean fileAssociationsChanged = contentModelManager.setFileAssociations(settings.getFileAssociations()); - if (fileAssociationsChanged) { - // Validate all opened XML files - context.collectDocumentToValidate(d -> { - DOMDocument xml = context.getDocument(d.getDocumentURI()); - xml.resetGrammar(); - return true; - }); - } - } - // Update use cache, only if it is set in the settings. - Boolean useCache = settings.isUseCache(); - if (useCache != null) { - contentModelManager.setUseCache(useCache); - } - // Update symbols - boolean showReferencedGrammars = settings.isShowReferencedGrammars(); - symbolsProviderParticipant.setEnabled(showReferencedGrammars); - // Track if validation settings has changed - XMLValidationSettings oldValidationSettings = currentValidationSettings; - currentValidationSettings = cmSettings.getValidation(); - if (oldValidationSettings != null && !Objects.equals(oldValidationSettings, currentValidationSettings)) { - context.collectDocumentToValidate(d -> true); - } - } - - @Override - public void start(InitializeParams params, XMLExtensionsRegistry registry) { - URIResolverExtensionManager resolverManager = registry.getComponent(URIResolverExtensionManager.class); - contentModelManager = new ContentModelManager(resolverManager); - registry.registerComponent(contentModelManager); - if (params != null) { - contentModelManager.setRootURI(params.getRootUri()); - } - documentLinkParticipant = new ContentModelDocumentLinkParticipant(resolverManager); - registry.registerCompletionParticipant(completionParticipant); - registry.registerHoverParticipant(hoverParticipant); - registry.registerDiagnosticsParticipant(diagnosticsParticipant); - registry.registerCodeActionParticipant(codeActionParticipant); - registry.registerDocumentLinkParticipant(documentLinkParticipant); - registry.registerTypeDefinitionParticipant(typeDefinitionParticipant); - symbolsProviderParticipant = new ContentModelSymbolsProviderParticipant(contentModelManager); - registry.registerSymbolsProviderParticipant(symbolsProviderParticipant); - codeLensParticipant = new ContentModelCodeLensParticipant(contentModelManager); - registry.registerCodeLensParticipant(codeLensParticipant); - documentTelemetryParticipant = new DocumentTelemetryParticipant(registry.getTelemetryManager(), contentModelManager); - registry.registerDocumentLifecycleParticipant(documentTelemetryParticipant); - - // Register custom commands to re-validate XML files - IXMLCommandService commandService = registry.getCommandService(); - if (commandService != null) { - IXMLValidationService validationService = registry.getValidationService(); - IXMLDocumentProvider documentProvider = registry.getDocumentProvider(); - commandService.registerCommand(XMLValidationFileCommand.COMMAND_ID, - new XMLValidationFileCommand(contentModelManager, documentProvider, validationService)); - commandService.registerCommand(XMLValidationAllFilesCommand.COMMAND_ID, - new XMLValidationAllFilesCommand(contentModelManager, documentProvider, validationService)); - commandService.registerCommand(AssociateGrammarCommand.COMMAND_ID, - new AssociateGrammarCommand(documentProvider)); - commandService.registerCommand(CheckBoundGrammarCommand.COMMAND_ID, - new CheckBoundGrammarCommand(documentProvider)); - commandService.registerCommand(CheckFilePatternCommand.COMMAND_ID, - new CheckFilePatternCommand()); - } - } - - @Override - public void stop(XMLExtensionsRegistry registry) { - registry.unregisterCompletionParticipant(completionParticipant); - registry.unregisterHoverParticipant(hoverParticipant); - registry.unregisterDiagnosticsParticipant(diagnosticsParticipant); - registry.unregisterCodeActionParticipant(codeActionParticipant); - registry.unregisterDocumentLinkParticipant(documentLinkParticipant); - registry.unregisterTypeDefinitionParticipant(typeDefinitionParticipant); - registry.unregisterSymbolsProviderParticipant(symbolsProviderParticipant); - registry.unregisterCodeLensParticipant(codeLensParticipant); - registry.unregisterDocumentLifecycleParticipant(documentTelemetryParticipant); - - // Un-register custom commands to re-validate XML files - IXMLCommandService commandService = registry.getCommandService(); - if (commandService != null) { - commandService.unregisterCommand(XMLValidationFileCommand.COMMAND_ID); - commandService.unregisterCommand(XMLValidationAllFilesCommand.COMMAND_ID); - commandService.unregisterCommand(AssociateGrammarCommand.COMMAND_ID); - commandService.unregisterCommand(CheckBoundGrammarCommand.COMMAND_ID); - commandService.unregisterCommand(CheckFilePatternCommand.COMMAND_ID); - } - } - - public ContentModelSettings getContentModelSettings() { - return cmSettings; - } - - public ContentModelManager getContentModelManager() { - return contentModelManager; - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/AssociateGrammarCommand.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/AssociateGrammarCommand.java deleted file mode 100644 index 1def77348..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/AssociateGrammarCommand.java +++ /dev/null @@ -1,182 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2021 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.contentmodel.commands; - -import static org.eclipse.lemminx.extensions.xsd.utils.XSDUtils.TARGET_NAMESPACE_ATTR; - -import java.net.URL; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.NoGrammarConstraintsCodeAction; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.extensions.commands.AbstractDOMDocumentCommandHandler; -import org.eclipse.lemminx.services.extensions.commands.ArgumentsUtils; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lemminx.utils.DOMUtils; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * XML Command "xml.associate.grammar.insert" to associate a grammar to a given - * DOM document. - * - * The command parameters {@link ExecuteCommandParams} must be filled with 3 - * parameters: - * - *
    - *
  • document URI (String) : the DOM document file URI to bind with a grammar. - *
  • - *
  • grammar URI (String) : the XSD, DTD file URI to bind with the DOM - * document.
  • - *
  • binding type (String) : which can takes values "standard", "xml-model" to - * know which binding type must be inserted in the DOM document.
  • - *
- * - * @author Angelo ZERR - * - */ -public class AssociateGrammarCommand extends AbstractDOMDocumentCommandHandler { - - public static final String COMMAND_ID = "xml.associate.grammar.insert"; - - public AssociateGrammarCommand(IXMLDocumentProvider documentProvider) { - super(documentProvider); - } - - public enum GrammarBindingType { - - STANDARD("standard"), // xsi:schemaLocation, xsi:noNamespaceSchemaLocation, DOCTYPE - XML_MODEL("xml-model"); // xml-model processing instruction - - private String name; - - private GrammarBindingType(String name) { - this.name = name != null ? name : name(); - } - - public String getName() { - return name; - } - } - - @SuppressWarnings({ "serial" }) - public static class UnknownBindingTypeException extends Exception { - - private final static String MESSAGE = "Unknown binding type ''{0}''. Allowed values are " + // - Stream.of(GrammarBindingType.values()) // - .map(GrammarBindingType::getName) // - .collect(Collectors.joining(", ", "[", "]")); - - public UnknownBindingTypeException(String bindingType) { - super(MessageFormat.format(MESSAGE, bindingType)); - } - - } - - @Override - protected Object executeCommand(DOMDocument document, ExecuteCommandParams params, SharedSettings sharedSettings, - CancelChecker cancelChecker) throws Exception { - String documentURI = document.getDocumentURI(); - String fullPathGrammarURI = ArgumentsUtils.getArgAt(params, 1, String.class); - String bindingType = ArgumentsUtils.getArgAt(params, 2, String.class); - String grammarURI = getRelativeURI(fullPathGrammarURI, documentURI); - boolean isXSD = DOMUtils.isXSD(fullPathGrammarURI); - - if (GrammarBindingType.STANDARD.getName().equals(bindingType)) { - if (isXSD) { - // XSD file - // Check if XSD to bind declares a target namespace - String targetNamespace = getTargetNamespace(fullPathGrammarURI); - if (StringUtils.isEmpty(targetNamespace)) { - // Insert inside -> - // xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance" - // xsi:noNamespaceSchemaLocation=\"xsd/tag.xsd\" - return NoGrammarConstraintsCodeAction.createXSINoNamespaceSchemaLocationEdit(grammarURI, document); - } - // Insert inside -> - // xmlns="team_namespace" - // xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - // xsi:schemaLocation="team_namespace xsd/team.xsd" - return NoGrammarConstraintsCodeAction.createXSISchemaLocationEdit(grammarURI, targetNamespace, - document); - } else { - // DTD file - // Insert before -> - return NoGrammarConstraintsCodeAction.createDocTypeEdit(grammarURI, document, sharedSettings); - } - } else if (GrammarBindingType.XML_MODEL.getName().equals(bindingType)) { - String targetNamespace = isXSD ? getTargetNamespace(fullPathGrammarURI) : null; - // Insert before -> - return NoGrammarConstraintsCodeAction.createXmlModelEdit(grammarURI, targetNamespace, document, - sharedSettings); - } - throw new UnknownBindingTypeException(bindingType); - } - - private static String getRelativeURI(String fullPathGrammarURI, String documentURI) { - try { - Path grammarPath = FilesUtils.getPath(fullPathGrammarURI); - Path documentPath = FilesUtils.getPath(documentURI); - Path relativePath = documentPath.getParent().relativize(grammarPath); - return relativePath.toString().replaceAll("\\\\", "/"); - } catch (Exception e) { - return fullPathGrammarURI; - } - } - - private static String getTargetNamespace(String xsdURI) { - TargetNamespaceHandler handler = new TargetNamespaceHandler(); - try { - SAXParserFactory factory = DOMUtils.newSAXParserFactory(); - SAXParser saxParser = factory.newSAXParser(); - saxParser.parse(new URL(xsdURI).openStream(), handler); - } catch (Exception e) { - - } - return handler.getTargetNamespace(); - } - - /** - * SAX handler which extract the targetNamespace attribute from the xs:schema - * root tag element and null otherwise. - * - */ - private static class TargetNamespaceHandler extends DefaultHandler { - - private String targetNamespace; - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - super.startElement(uri, localName, qName, attributes); - this.targetNamespace = attributes.getValue(TARGET_NAMESPACE_ATTR); - throw new SAXException(); - } - - public String getTargetNamespace() { - return targetNamespace; - } - } - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckBoundGrammarCommand.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckBoundGrammarCommand.java deleted file mode 100644 index 32dae57c6..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckBoundGrammarCommand.java +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2021 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.contentmodel.commands; - -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.extensions.commands.AbstractDOMDocumentCommandHandler; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * XML Command "xml.check.bound.grammar" to verify if an XML document already - * has a bound grammar/schema, opened from the command palette. - * - */ -public class CheckBoundGrammarCommand extends AbstractDOMDocumentCommandHandler { - - public static final String COMMAND_ID = "xml.check.bound.grammar"; - - public CheckBoundGrammarCommand(IXMLDocumentProvider documentProvider) { - super(documentProvider); - } - - @Override - protected Object executeCommand(DOMDocument document, ExecuteCommandParams params, SharedSettings sharedSettings, - CancelChecker cancelChecker) throws Exception { - // Check if the document has a bound grammar. - return canBindWithGrammar(document); - } - - /** - * Returns true if the given DOM document can be bound with a given grammar and - * false otherwise. - * - * @param document the DOM document. - * - * @return true if the given DOM document can be bound with a given grammar and - * false otherwise. - */ - public static boolean canBindWithGrammar(DOMDocument document) { - DOMElement documentElement = document.getDocumentElement(); - if (documentElement == null) { - return false; - } - return !document.hasGrammar(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckFilePatternCommand.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckFilePatternCommand.java deleted file mode 100644 index 13a67b789..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/CheckFilePatternCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2021 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.contentmodel.commands; - -import org.eclipse.lemminx.services.extensions.commands.ArgumentsUtils; -import org.eclipse.lemminx.services.extensions.commands.IXMLCommandService.IDelegateCommandHandler; -import org.eclipse.lemminx.settings.PathPatternMatcher; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * XML Command "xml.check.file.pattern" whose first argument is a file pattern, - * and whose second argument is some file URI. The command returns true when - * the given pattern matches against the given file URI and false otherwise. - */ -public class CheckFilePatternCommand implements IDelegateCommandHandler { - - public static final String COMMAND_ID = "xml.check.file.pattern"; - - @Override - public Object executeCommand(ExecuteCommandParams params, SharedSettings sharedSettings, - CancelChecker cancelChecker) throws Exception { - String pattern = ArgumentsUtils.getArgAt(params, 0, String.class); - String currentUri = ArgumentsUtils.getArgAt(params, 1, String.class); - PathPatternMatcher matcher = new PathPatternMatcher(); - matcher.setPattern(pattern); - return matcher.matches(currentUri); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationAllFilesCommand.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationAllFilesCommand.java deleted file mode 100644 index b5a7e694d..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationAllFilesCommand.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.contentmodel.commands; - -import java.util.Collection; - -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.IXMLValidationService; -import org.eclipse.lemminx.services.extensions.commands.IXMLCommandService.IDelegateCommandHandler; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * XML Command "xml.validation.all.files" to revalidate all opened XML files - * which means: - * - *
    - *
  • clear the Xerces grammar pool (used by the Xerces validation) and the - * content model documents cache (used by the XML completion/hover based on the - * grammar)
  • - *
  • trigger the validation for the all opened XML files
  • - *
- * - * @author Angelo ZERR - * - */ -public class XMLValidationAllFilesCommand implements IDelegateCommandHandler { - - public static final String COMMAND_ID = "xml.validation.all.files"; - - private final ContentModelManager contentModelManager; - - private final IXMLDocumentProvider documentProvider; - - private final IXMLValidationService validationService; - - public XMLValidationAllFilesCommand(ContentModelManager contentModelManager, IXMLDocumentProvider documentProvider, - IXMLValidationService validationService) { - this.contentModelManager = contentModelManager; - this.documentProvider = documentProvider; - this.validationService = validationService; - } - - @Override - public Object executeCommand(ExecuteCommandParams params, SharedSettings sharedSettings, - CancelChecker cancelChecker) throws Exception { - // 1. clear the Xerces grammar pool - // (used by the Xerces validation) and the content model documents cache (used - // by the XML completion/hover based on the grammar) - contentModelManager.evictCache(); - // 2. trigger the validation for the all opened XML files - Collection all = documentProvider.getAllDocuments(); - for (DOMDocument document : all) { - validationService.validate(document); - } - return null; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationFileCommand.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationFileCommand.java deleted file mode 100644 index 3c9b07e1b..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/commands/XMLValidationFileCommand.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2020 Red Hat Inc. and others. -* All rights reserved. This program and the accompanying materials -* which accompanies this distribution, and is available at -* http://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Contributors: -* Red Hat Inc. - initial API and implementation -*******************************************************************************/ -package org.eclipse.lemminx.extensions.contentmodel.commands; - -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager; -import org.eclipse.lemminx.services.IXMLDocumentProvider; -import org.eclipse.lemminx.services.IXMLValidationService; -import org.eclipse.lemminx.services.extensions.commands.AbstractDOMDocumentCommandHandler; -import org.eclipse.lemminx.settings.SharedSettings; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.jsonrpc.CancelChecker; - -/** - * XML Command "xml.validation.current.file" to revalidate a give XML file which - * means: - * - *
    - *
  • remove the referenced grammar in the XML file from the Xerces grammar - * pool (used by the Xerces validation) and the content model documents cache - * (used by the XML completion/hover based on the grammar)
  • - *
  • trigger the validation for the given XML file
  • - *
- * - * @author Angelo ZERR - * - */ -public class XMLValidationFileCommand extends AbstractDOMDocumentCommandHandler { - - public static final String COMMAND_ID = "xml.validation.current.file"; - - private final ContentModelManager contentModelManager; - - private final IXMLValidationService validationService; - - public XMLValidationFileCommand(ContentModelManager contentModelManager, IXMLDocumentProvider documentProvider, - IXMLValidationService validationService) { - super(documentProvider); - this.contentModelManager = contentModelManager; - this.validationService = validationService; - } - - @Override - protected Object executeCommand(DOMDocument document, ExecuteCommandParams params, SharedSettings sharedSettings, - CancelChecker cancelChecker) throws Exception { - // 1. remove the referenced grammar in the XML file from the Xerces grammar pool - // (used by the Xerces validation) and the content model documents cache (used - // by the XML completion/hover based on the grammar) - contentModelManager.evictCacheFor(document); - // 2. trigger the validation for the given XML file - validationService.validate(document); - return null; - } - -} \ No newline at end of file diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMAttributeDeclaration.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMAttributeDeclaration.java deleted file mode 100644 index 56a322083..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMAttributeDeclaration.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.contentmodel.model; - -import java.util.Collection; - -import org.eclipse.lemminx.services.extensions.ISharedSettingsRequest; - -/** - * Content model element which abstracts attribute declaration from a given - * grammar (XML Schema, DTD). - */ -public interface CMAttributeDeclaration { - - /** - * Returns the declared element name. - * - * @return the declared element name. - */ - String getName(); - - String getDefaultValue(); - - Collection getEnumerationValues(); - - /** - * Returns formatted documentation of the declared - * attribute according to settings defined in request - * - * @param request the request that contains settings - * @return formatted documentation of the declared - * attribute according to settings defined in request - */ - String getAttributeNameDocumentation(ISharedSettingsRequest request); - - /** - * Returns formatted documentation about value, - * according to settings defined in request - * - * @param value the attribute value to find documentation for - * @param request the request containing settings - * @return formatted documentation about value, - * according to settings defined in request - */ - String getAttributeValueDocumentation(String value, ISharedSettingsRequest request); - - /** - * Returns true if the attribute is required and false otherwise. - * - * @return true if the attribute is required and false otherwise. - */ - boolean isRequired(); -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMDocument.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMDocument.java deleted file mode 100644 index f514d134e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMDocument.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.contentmodel.model; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.dom.DOMNode; -import org.eclipse.lsp4j.LocationLink; -import org.w3c.dom.Entity; - -/** - * Content model document which abstracts element declaration from a given - * grammar (XML Schema, DTD). - */ -public interface CMDocument { - - /** - * Returns true if the model document defines the given namespace and false - * otherwise. - * - * @param namespaceURI - * @return true if the model document defines the given namespace and false - * otherwise. - */ - boolean hasNamespace(String namespaceURI); - - /** - * Returns the elements declaration of the model document root. - * - * @return the elements declaration of the model document root. - */ - Collection getElements(); - - /** - * Returns the declared element which matches the given XML element and null - * otherwise. - * - * @param element the XML element - * @return the declared element which matches the given XML element and null - * otherwise. - */ - default CMElementDeclaration findCMElement(DOMElement element) { - return findCMElement(element, element.getNamespaceURI()); - } - - /** - * Returns the declared element which matches the given XML element and null - * otherwise. - * - * @param element the XML element - * @param namespace the given namespace - * @return the declared element which matches the given XML element and null - * otherwise. - */ - CMElementDeclaration findCMElement(DOMElement element, String namespace); - - default CMAttributeDeclaration findCMAttribute(DOMElement element, String attributeName) { - CMElementDeclaration elementDeclaration = findCMElement(element); - return elementDeclaration != null ? elementDeclaration.findCMAttribute(attributeName) : null; - } - - /** - * Returns the location of the type definition of the given node. - * - * @param node the node - * @return the location of the type definition of the given node. - */ - LocationLink findTypeLocation(DOMNode node); - - /** - * Returns true if the content model document is dirty and false otherwise. - * - * @return true if the content model document is dirty and false otherwise. - */ - boolean isDirty(); - - /** - * Returns list of declared entities. - * - * @return list of declared entities. - */ - default List getEntities() { - return Collections.emptyList(); - } -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMElementDeclaration.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMElementDeclaration.java deleted file mode 100644 index 91df3937e..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/CMElementDeclaration.java +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.contentmodel.model; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.services.extensions.ISharedSettingsRequest; - -/** - * Content model element which abstracts element declaration from a given - * grammar (XML Schema, DTD). - */ -public interface CMElementDeclaration { - - public static final Collection ANY_ELEMENT_DECLARATIONS = Collections - .unmodifiableCollection(Arrays.asList()); - - /** - * Returns the declared element name. - * - * @return the declared element name. - */ - String getName(); - - /** - * Returns the target namespace and null otherwise. - * - * @return the target namespace and null otherwise. - */ - String getNamespace(); - - /** - * Returns the declared element name with the given prefix. - * - * @return the declared element name with the given prefix. - */ - default String getName(String prefix) { - String name = getName(); - if (prefix == null || prefix.isEmpty()) { - return name; - } - return prefix + ":" + name; - } - - /** - * Returns the attributes of this declared element. - * - * @return the attributes element of this declared element. - */ - Collection getAttributes(); - - /** - * Returns the children declared element of this declared element. - * - * @return the children declared element of this declared element. - */ - Collection getElements(); - - /** - * Returns the possible declared elements at the given offset of the given - * parent element. - * - * @param parentElement the parent element - * @param offset the offset - * @return the possible declared elements at the given offset of the given - * parent element. - */ - Collection getPossibleElements(DOMElement parentElement, int offset); - - /** - * Returns the declared element which matches the given XML tag name / namespace - * and null otherwise. - * - * @param tag - * @param namespace - * @return the declared element which matches the given XML tag name / namespace - * and null otherwise. - */ - CMElementDeclaration findCMElement(String tag, String namespace); - - /** - * Returns the declared attribute which match the given name and null otherwise. - * - * @param attributeName - * @return the declared attribute which match the given name and null otherwise. - */ - CMAttributeDeclaration findCMAttribute(String attributeName); - - /** - * Returns formatted documentation of the declared element, according to - * settings defined in request. - * - * @param request the request containing settings - * @return formatted documentation of the declared element, according to - * settings defined in request. - */ - String getDocumentation(ISharedSettingsRequest request); - - /** - * Returns true if the element cannot contains element children or text content - * and false otherwise. - * - * @return true if the element cannot contains element children or text content - * and false otherwise. - */ - boolean isEmpty(); - - /** - * Return the enumeration values. - * - * @return the enumeration values. - */ - Collection getEnumerationValues(); - - /** - * Returns the documentation for the given enumeration value and null otherwise. - * - * @param value the enumeration value. - * @param request the shared settings. - * - * @return the documentation for the given enumeration value and null otherwise. - */ - String getTextDocumentation(String value, ISharedSettingsRequest request); - - /** - * Returns the owner document URI where the element is declared. - * - * @return the owner document URI where the element is declared. - */ - String getDocumentURI(); - -} diff --git a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/ContentModelManager.java b/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/ContentModelManager.java deleted file mode 100644 index 02ebc0f59..000000000 --- a/lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/model/ContentModelManager.java +++ /dev/null @@ -1,477 +0,0 @@ -/** - * Copyright (c) 2018 Angelo ZERR - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Angelo Zerr - initial API and implementation - */ -package org.eclipse.lemminx.extensions.contentmodel.model; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.xerces.xni.grammars.XMLGrammarPool; -import org.eclipse.lemminx.dom.DOMDocument; -import org.eclipse.lemminx.dom.DOMElement; -import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelProvider.Identifier; -import org.eclipse.lemminx.extensions.contentmodel.participants.diagnostics.LSPXMLGrammarPool; -import org.eclipse.lemminx.extensions.contentmodel.settings.XMLFileAssociation; -import org.eclipse.lemminx.extensions.contentmodel.uriresolver.XMLCacheResolverExtension; -import org.eclipse.lemminx.extensions.contentmodel.uriresolver.XMLCatalogResolverExtension; -import org.eclipse.lemminx.extensions.contentmodel.uriresolver.XMLFileAssociationResolverExtension; -import org.eclipse.lemminx.uriresolver.CacheResourceDownloadingException; -import org.eclipse.lemminx.uriresolver.CacheResourcesManager; -import org.eclipse.lemminx.uriresolver.ResolvedURIInfo; -import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lemminx.utils.StringUtils; -import org.eclipse.lemminx.utils.URIUtils; - -/** - * Content model manager used to load XML Schema, DTD. - * - */ -public class ContentModelManager { - - private final Map cmDocumentCache; - - private final URIResolverExtensionManager resolverManager; - private final List modelProviders; - - private final XMLCacheResolverExtension cacheResolverExtension; - private final XMLCatalogResolverExtension catalogResolverExtension; - private final XMLFileAssociationResolverExtension fileAssociationResolver; - private final XMLGrammarPool grammarPool; - - public ContentModelManager(URIResolverExtensionManager resolverManager) { - this.resolverManager = resolverManager; - modelProviders = new ArrayList<>(); - cmDocumentCache = Collections.synchronizedMap(new HashMap<>()); - fileAssociationResolver = new XMLFileAssociationResolverExtension(); - resolverManager.registerResolver(fileAssociationResolver); - catalogResolverExtension = new XMLCatalogResolverExtension(); - resolverManager.registerResolver(catalogResolverExtension); - cacheResolverExtension = new XMLCacheResolverExtension(); - resolverManager.registerResolver(cacheResolverExtension); - grammarPool = new LSPXMLGrammarPool(); - // Use cache by default - setUseCache(true); - } - - /** - * Returns the owner document of the declared element which matches the given - * XML element and null otherwise. - * - * @param element the XML element - * - * @return the owner document of the declared element which matches the given - * XML element and null otherwise. - */ - public Collection findCMDocument(DOMElement element) { - return findCMDocument(element.getOwnerDocument(), element.getNamespaceURI()); - } - - /** - * Returns the owner document of the declared element which matches the given - * XML element and null otherwise. - * - * @param element the XML element - * - * @return the owner document of the declared element which matches the given - * XML element and null otherwise. - */ - public Collection findCMDocument(DOMElement element, String namespaceURI) { - return findCMDocument(element.getOwnerDocument(), namespaceURI); - } - - public Collection findCMDocument(DOMDocument xmlDocument, String namespaceURI) { - return findCMDocument(xmlDocument, namespaceURI, true); - } - - /** - * Returns the declared documents which match the given DOM document. - * - * @param xmlDocument the DOM document. - * @param namespaceURI the namespace URI - * @return the declared documents which match the given DOM document. - */ - public Collection findCMDocument(DOMDocument xmlDocument, String namespaceURI, boolean withInternal) { - if (namespaceURI == null) { - // This case comes from when an element has no namespace and XML Schema defines - // elementFormDefault="unqualified" - // --> we use the namespace from the DOM document - - // ex: XSD: - // - // --> here template has a null namespace and the DOM document has - // "urn:reports/itops" namespace - // --> we use urn:reports/itops as namespace to get the DOM Document - namespaceURI = xmlDocument.getNamespaceURI(); - } - Collection documents = new ArrayList<>(); - for (ContentModelProvider modelProvider : modelProviders) { - // internal grammar - if (withInternal) { - CMDocument internalCMDocument = modelProvider.createInternalCMDocument(xmlDocument); - if (internalCMDocument != null) { - documents.add(internalCMDocument); - } - } - // external grammar - if (modelProvider.adaptFor(xmlDocument, false)) { - // The content model provider can collect the system ids - // ex for identifiers = modelProvider.getIdentifiers(xmlDocument, namespaceURI); - for (Identifier identifier : identifiers) { - String systemId = identifier.getSystemId(); - String publicId = identifier.getPublicId() != null ? identifier.getPublicId() : namespaceURI; - // get the content model document from the current system id - CMDocument cmDocument = findCMDocument(xmlDocument.getDocumentURI(), publicId, systemId, - modelProvider); - if (cmDocument != null) { - documents.add(cmDocument); - } - } - } - } - if (documents.isEmpty()) { - CMDocument cmDocument = findCMDocument(xmlDocument.getDocumentURI(), namespaceURI, null, null); - if (cmDocument != null) { - documents.add(cmDocument); - } - } - return documents; - } - - /** - * Returns true if the given document is linked to the given grammar URI (XML - * Schema, DTD) and false otherwise. - * - * @param document the DOM document - * @param grammarURI the grammar URI - * @return true if the given document is linked to the given grammar URI (XML - * Schema, DTD) and false otherwise. - */ - public boolean dependsOnGrammar(DOMDocument document, String grammarURI) { - if (StringUtils.isEmpty(grammarURI)) { - return false; - } - for (ContentModelProvider modelProvider : modelProviders) { - if (modelProvider.adaptFor(document, false)) { - Collection identifiers = modelProvider.getIdentifiers(document, document.getNamespaceURI()); - for (Identifier identifier : identifiers) { - String publicId = identifier.getPublicId(); - String systemId = identifier.getSystemId(); - String key = resolverManager.resolve(document.getDocumentURI(), publicId, systemId); - if (grammarURI.equals(key)) { - return true; - } - } - } - } - String key = resolverManager.resolve(document.getDocumentURI(), null, null); - return grammarURI.equals(key); - } - - /** - * Returns informations about all referenced grammar (XSD, DTD) from the given - * DOM document. - * - *

- * In other words, it gives information about - * - *