You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ma...@apache.org on 2020/02/29 09:34:56 UTC

[netbeans] branch master updated: Hook formating/rangeFormating into LSP Client

This is an automated email from the ASF dual-hosted git repository.

matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c464af0  Hook formating/rangeFormating into LSP Client
     new a5aae4a  Merge pull request #1955 from matthiasblaesing/lsp_formating
c464af0 is described below

commit c464af06b7a0b94f65fa8cdd5d2533863a9746a3
Author: Matthias Bläsing <mb...@doppel-helix.eu>
AuthorDate: Tue Feb 18 22:30:04 2020 +0100

    Hook formating/rangeFormating into LSP Client
---
 .../src/org/netbeans/modules/lsp/client/Utils.java |  41 ++++++-
 .../modules/lsp/client/bindings/Formatter.java     | 136 +++++++++++++++++++++
 2 files changed, 174 insertions(+), 3 deletions(-)

diff --git a/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
index c67722b..278cfbc 100644
--- a/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
+++ b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
@@ -24,6 +24,7 @@ import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
@@ -140,15 +141,37 @@ public class Utils {
     }
 
     public static void applyEditsNoLock(Document doc, List<? extends TextEdit> edits) {
+        applyEditsNoLock(doc, edits, null, null);
+    }
+
+    /**
+     * Apply edits to the document. The edits can be filtered to only cover
+     * parts of the documents.
+     *
+     * @param doc        {@link Document} the edits shall be applied to
+     * @param edits      list {@link TextEdit} to apply
+     * @param startLimit if not {@code null} only edits with a {@code start}
+     *                   larger than or equals to this offset are considered.
+     *                   The offset is expected to be apply to the original
+     *                   state of the document.
+     * @param endLimit   if not {@code null} only edits with an {@code end}
+     *                   lower than this offset are considered. The offset is
+     *                   expected to be apply to the original state of the
+     *                   document.
+     */
+    public static void applyEditsNoLock(Document doc, List<? extends TextEdit> edits, Integer startLimit, Integer endLimit) {
         edits
          .stream()
-         .sorted((te1, te2) -> te1.getRange().getEnd().getLine() == te2.getRange().getEnd().getLine() ? te1.getRange().getEnd().getCharacter() - te2.getRange().getEnd().getCharacter() : te1.getRange().getEnd().getLine() - te2.getRange().getEnd().getLine())
+         .sorted(rangeReverseSort)
          .forEach(te -> {
             try {
                 int start = Utils.getOffset(doc, te.getRange().getStart());
                 int end = Utils.getOffset(doc, te.getRange().getEnd());
-                doc.remove(start, end - start);
-                doc.insertString(start, te.getNewText(), null);
+                if ((startLimit == null || start >= startLimit)
+                    && (endLimit == null || end < endLimit)) {
+                    doc.remove(start, end - start);
+                    doc.insertString(start, te.getNewText(), null);
+                }
             } catch (BadLocationException ex) {
                 Exceptions.printStackTrace(ex);
             }
@@ -247,4 +270,16 @@ public class Utils {
             Exceptions.printStackTrace(ex);
         }
     }
+
+    private static final Comparator<TextEdit> rangeReverseSort = (s1, s2) -> {
+        int l1 = s1.getRange().getEnd().getLine();
+        int l2 = s2.getRange().getEnd().getLine();
+        int c1 = s1.getRange().getEnd().getCharacter();
+        int c2 = s2.getRange().getEnd().getCharacter();
+        if (l1 != l2) {
+            return l2 - l1;
+        } else {
+            return c2 - c1;
+        }
+    };
 }
diff --git a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Formatter.java b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Formatter.java
new file mode 100644
index 0000000..f399461
--- /dev/null
+++ b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Formatter.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.lsp.client.bindings;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.StyledDocument;
+import org.eclipse.lsp4j.DocumentFormattingParams;
+import org.eclipse.lsp4j.DocumentRangeFormattingParams;
+import org.eclipse.lsp4j.FormattingOptions;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.TextEdit;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.modules.editor.NbEditorUtilities;
+import org.netbeans.modules.editor.indent.api.IndentUtils;
+import org.netbeans.modules.editor.indent.spi.Context;
+import org.netbeans.modules.editor.indent.spi.ExtraLock;
+import org.netbeans.modules.editor.indent.spi.ReformatTask;
+import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
+import org.openide.filesystems.FileObject;
+import org.openide.text.NbDocument;
+
+public class Formatter implements ReformatTask {
+
+    private static final Logger LOG = Logger.getLogger(Formatter.class.getName());
+
+    @MimeRegistration(mimeType = "", service = ReformatTask.Factory.class)
+    public static class Factory implements ReformatTask.Factory {
+
+        @Override
+        public ReformatTask createTask(Context context) {
+            return new Formatter(context);
+        }
+
+    }
+
+    private final Context ctx;
+
+    public Formatter(Context ctx) {
+        this.ctx = ctx;
+    }
+
+    @Override
+    public void reformat() throws BadLocationException {
+        FileObject file = NbEditorUtilities.getFileObject(ctx.document());
+        if(file != null) {
+            LSPBindings bindings = LSPBindings.getBindings(file);
+            if (bindings != null) {
+                Boolean documentFormatting = bindings.getInitResult().getCapabilities().getDocumentFormattingProvider();
+                Boolean rangeFormatting = bindings.getInitResult().getCapabilities().getDocumentRangeFormattingProvider();
+                if (rangeFormatting != null && rangeFormatting) {
+                    rangeFormat(file, bindings);
+                } else if (documentFormatting != null && documentFormatting) {
+                    documentFormat(file, bindings);
+                }
+            }
+        }
+    }
+
+    private void rangeFormat(FileObject fo, LSPBindings bindings) throws BadLocationException {
+        DocumentRangeFormattingParams drfp = new DocumentRangeFormattingParams();
+        drfp.setTextDocument(new TextDocumentIdentifier(Utils.toURI(fo)));
+        drfp.setOptions(new FormattingOptions(
+            IndentUtils.indentLevelSize(ctx.document()),
+            IndentUtils.isExpandTabs(ctx.document())));
+        drfp.setRange(new Range(
+            Utils.createPosition(ctx.document(), ctx.startOffset()),
+            Utils.createPosition(ctx.document(), ctx.endOffset())));
+        List<TextEdit> edits = new ArrayList<>();
+        try {
+            edits = new ArrayList<>(bindings.getTextDocumentService().rangeFormatting(drfp).get());
+        } catch (InterruptedException | ExecutionException ex) {
+            LOG.log(Level.INFO,
+                String.format("LSP document rangeFormat failed for {0}", fo),
+                ex);
+        }
+
+        applyTextEdits(edits);
+    }
+
+    private void documentFormat(FileObject fo, LSPBindings bindings) throws BadLocationException {
+        DocumentFormattingParams dfp = new DocumentFormattingParams();
+        dfp.setTextDocument(new TextDocumentIdentifier(Utils.toURI(fo)));
+        dfp.setOptions(new FormattingOptions(
+            IndentUtils.indentLevelSize(ctx.document()),
+            IndentUtils.isExpandTabs(ctx.document())));
+        List<TextEdit> edits = new ArrayList<>();
+        try {
+            edits.addAll(bindings.getTextDocumentService().formatting(dfp).get());
+        } catch (InterruptedException | ExecutionException ex) {
+            LOG.log(Level.INFO,
+                String.format("LSP document format failed for {0}", fo),
+                ex);
+        }
+
+        applyTextEdits(edits);
+    }
+
+    private void applyTextEdits(List<TextEdit> edits) {
+        if(ctx.document() instanceof StyledDocument) {
+            NbDocument.runAtomic((StyledDocument) ctx.document(), () -> {
+                Utils.applyEditsNoLock(ctx.document(), edits, ctx.startOffset(), ctx.endOffset());
+            });
+        } else {
+            Utils.applyEditsNoLock(ctx.document(), edits, ctx.startOffset(), ctx.endOffset());
+        }
+    }
+
+    @Override
+    public ExtraLock reformatLock() {
+        return null;
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists