Repository: clojure-lsp/clojure-lsp (clojure)

Issue:
Prevent negative numbers in diagnostics ranges
While working on integrating clojure-lsp with Calva I've noticed this error sometimes:

```text
Notification handler 'textDocument/publishDiagnostics' failed with message: Illegal argument: line must be non-negative
```

When I examined those message types in the trace logs, I see that sometimes a message like this is sent from the server:

```json
{
  "uri": "file:///home/brandon/development/clojure-test/.calva/output-window/output.calva-repl",
  "diagnostics": [
    {
      "range": {
        "start": {
          "line": -1,
          "character": -1
        },
        "end": {
          "line": -1,
          "character": -1
        }
      },
      "severity": 1,
      "code": "syntax",
      "source": "clj-kondo",
      "message": "Can't parse <stdin>, No matching clause: :unknown"
    }
  ]
}
```

After tracing through the code, I'm guessing clj-kondo is providing a row/col of 0/0 when trying to lint Calva's `output.calva-repl` file, which Calva labels as Clojure so that it gets Clojure syntax highlighting, Calva features, etc. Due to its not normal formatting it probably causes parsing errors in clj-kondo. These 0/0 numbers are then decremented to -1/-1 here:

https://github.com/snoe/clojure-lsp/blob/8b984cb261e05d96471f5d6056a1c7ad05675bb5/src/clojure_lsp/shared.clj#L16

I know Calva's usage with this file is not conventional, but since the lsp spec says ranges should contain negative numbers, do you think clojure-lsp should prevent negative numbers in the above function, by either leaving them at 0 if they are 0, or setting them to 0 if they're negative after decrementing?

Pull request:
Also added tests for `clojure-lsp.shared/->range`, one of which covers this case.

Fixes #198

Patch:
diff --git a/src/clojure_lsp/shared.clj b/src/clojure_lsp/shared.clj
index 2b661b16a..88859ab55 100644
--- a/src/clojure_lsp/shared.clj
+++ b/src/clojure_lsp/shared.clj
@@ -14,8 +14,8 @@
     :else :unknown))
 
 (defn ->range [{:keys [row end-row col end-col]}]
-  {:start {:line (dec row) :character (dec col)}
-   :end {:line (dec end-row) :character (dec end-col)}})
+  {:start {:line (max 0 (dec row)) :character (max 0 (dec col))}
+   :end {:line (max 0 (dec end-row)) :character (max 0 (dec end-col))}})
 
 (defn range->clj [^Range range]
   {:start {:line      (.getLine (.getStart range))


Test patch:
diff --git a/test/clojure_lsp/shared_test.clj b/test/clojure_lsp/shared_test.clj
new file mode 100644
index 000000000..b6b2e08b2
--- /dev/null
+++ b/test/clojure_lsp/shared_test.clj
@@ -0,0 +1,17 @@
+(ns clojure-lsp.shared-test
+  (:require [clojure-lsp.shared :as shared]
+            [clojure.test :refer [deftest testing is]]))
+
+(deftest ->range-test
+  (testing "should subtract 1 from row and col values"
+    (is (= {:start {:line      1
+                    :character 1}
+            :end   {:line      1
+                    :character 1}}
+           (shared/->range {:row 2 :end-row 2 :col 2 :end-col 2}))))
+  (testing "should not return negative line and character values"
+    (is (= {:start {:line      0
+                    :character 0}
+            :end   {:line      0
+                    :character 0}}
+           (shared/->range {:row 0 :end-row 0 :col 0 :end-col 0})))))
\ No newline at end of file