Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use complete exception: args-out-of-range #<buffer args_out_of_range.c> 110 124 #860

Closed
archer-n opened this issue Mar 5, 2022 · 31 comments
Labels

Comments

@archer-n
Copy link

archer-n commented Mar 5, 2022

  • Server used: clangd version 13.0.1
  • Emacs version: GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.32, cairo version 1.17.4) of 2022-03-05
  • Operating system: Arch Linux x86_64
  • Eglot version: 20220302.1035 or 8dc5180
  • Eglot installation method: package.el
  • Using Doom: No

LSP transcript - M-x eglot-events-buffer (mandatory unless Emacs inoperable)

[internal] Sat Mar  5 12:44:35 2022:
(:message "Running language server: /usr/bin/clangd")
[client-request] (id:1) Sat Mar  5 12:44:35 2022:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
	  (:processId 26406 :rootPath "/home/archer/workspace/test/" :rootUri "file:///home/archer/workspace/test" :initializationOptions #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
																			())
		      :capabilities
		      (:workspace
		       (:applyEdit t :executeCommand
				   (:dynamicRegistration :json-false)
				   :workspaceEdit
				   (:documentChanges :json-false)
				   :didChangeWatchedFiles
				   (:dynamicRegistration t)
				   :symbol
				   (:dynamicRegistration :json-false)
				   :configuration t)
		       :textDocument
		       (:synchronization
			(:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
			:completion
			(:dynamicRegistration :json-false :completionItem
					      (:snippetSupport :json-false :deprecatedSupport t :tagSupport
							       (:valueSet
								[1]))
					      :contextSupport t)
			:hover
			(:dynamicRegistration :json-false :contentFormat
					      ["plaintext"])
			:signatureHelp
			(:dynamicRegistration :json-false :signatureInformation
					      (:parameterInformation
					       (:labelOffsetSupport t)
					       :activeParameterSupport t))
			:references
			(:dynamicRegistration :json-false)
			:definition
			(:dynamicRegistration :json-false :linkSupport t)
			:declaration
			(:dynamicRegistration :json-false :linkSupport t)
			:implementation
			(:dynamicRegistration :json-false :linkSupport t)
			:typeDefinition
			(:dynamicRegistration :json-false :linkSupport t)
			:documentSymbol
			(:dynamicRegistration :json-false :hierarchicalDocumentSymbolSupport t :symbolKind
					      (:valueSet
					       [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
			:documentHighlight
			(:dynamicRegistration :json-false)
			:codeAction
			(:dynamicRegistration :json-false :codeActionLiteralSupport
					      (:codeActionKind
					       (:valueSet
						["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"]))
					      :isPreferredSupport t)
			:formatting
			(:dynamicRegistration :json-false)
			:rangeFormatting
			(:dynamicRegistration :json-false)
			:rename
			(:dynamicRegistration :json-false)
			:publishDiagnostics
			(:relatedInformation :json-false :codeDescriptionSupport :json-false :tagSupport
					     (:valueSet
					      [1 2])))
		       :experimental #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
						   ()))))
[stderr] I[12:44:35.946] clangd version 13.0.1
[stderr] I[12:44:35.946] Features: linux
[stderr] I[12:44:35.946] PID: 26427
[stderr] I[12:44:35.946] Working directory: /home/archer/workspace/test
[stderr] I[12:44:35.946] argv[0]: /usr/bin/clangd
[stderr] I[12:44:35.946] Starting LSP over stdin/stdout
[server-reply] (id:1) Sat Mar  5 12:44:35 2022:
(:id 1 :jsonrpc "2.0" :result
     (:capabilities
      (:astProvider t :callHierarchyProvider t :codeActionProvider
		    (:codeActionKinds
		     ["quickfix" "refactor" "info"])
		    :compilationDatabase
		    (:automaticReload t)
		    :completionProvider
		    (:allCommitCharacters
		     [" " "	" "(" ")" "[" "]" "{" "}" "<" ">" ":" ";" "," "+" "-" "/" "*" "%" "^" "&" "#" "?" "." "=" "\"" "'" "|"]
		     :resolveProvider :json-false :triggerCharacters
		     ["." "<" ">" ":" "\"" "/"])
		    :declarationProvider t :definitionProvider t :documentFormattingProvider t :documentHighlightProvider t :documentLinkProvider
		    (:resolveProvider :json-false)
		    :documentOnTypeFormattingProvider
		    (:firstTriggerCharacter "\n" :moreTriggerCharacter
					    [])
		    :documentRangeFormattingProvider t :documentSymbolProvider t :executeCommandProvider
		    (:commands
		     ["clangd.applyFix" "clangd.applyTweak"])
		    :hoverProvider t :implementationProvider t :memoryUsageProvider t :referencesProvider t :renameProvider t :selectionRangeProvider t :semanticTokensProvider
		    (:full
		     (:delta t)
		     :legend
		     (:tokenModifiers
		      ["declaration" "deprecated" "deduced" "readonly" "static" "abstract" "dependentName" "defaultLibrary" "functionScope" "classScope" "fileScope" "globalScope"]
		      :tokenTypes
		      ["variable" "variable" "parameter" "function" "method" "function" "property" "variable" "class" "interface" "enum" "enumMember" "type" "type" "unknown" "namespace" "typeParameter" "concept" "type" "macro" "comment"])
		     :range :json-false)
		    :signatureHelpProvider
		    (:triggerCharacters
		     ["(" ","])
		    :textDocumentSync
		    (:change 2 :openClose t :save t)
		    :typeHierarchyProvider t :workspaceSymbolProvider t)
      :serverInfo
      (:name "clangd" :version "clangd version 13.0.1 linux x86_64-pc-linux-gnu")))
[client-notification] Sat Mar  5 12:44:35 2022:
(:jsonrpc "2.0" :method "initialized" :params #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
							    ()))
[client-notification] Sat Mar  5 12:44:35 2022:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c" :version 0 :languageId "c" :text "struct Book {\n  int id;\n  char title[50]\n} book = { 1024, \"C\" };\n\nint main(int argc, char *argv[])\n{\n\n  // Error when typing \"book.\"\n  book\n  return 0;\n}\n")))
[client-notification] Sat Mar  5 12:44:35 2022:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
	  (:settings nil))
[server-notification] Sat Mar  5 12:44:36 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
	  (:diagnostics
	   [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix available)" :range
		   (:end
		    (:character 1 :line 3)
		    :start
		    (:character 0 :line 3))
		   :severity 2 :source "clang")
	    (:code "expected_semi_after_expr" :message "Expected ';' after expression (fix available)" :range
		   (:end
		    (:character 8 :line 10)
		    :start
		    (:character 2 :line 10))
		   :severity 1 :source "clang")
	    (:code "-Wunused-value" :message "Expression result unused" :range
		   (:end
		    (:character 6 :line 9)
		    :start
		    (:character 2 :line 9))
		   :severity 2 :source "clang")]
	   :uri "file:///home/archer/workspace/test/args_out_of_range.c" :version 0))
[stderr] I[12:44:35.946] <-- initialize(1)
[stderr] I[12:44:35.948] --> reply:initialize(1) 1 ms
[stderr] I[12:44:35.950] <-- initialized
[stderr] I[12:44:35.952] <-- textDocument/didOpen
[stderr] I[12:44:35.953] <-- workspace/didChangeConfiguration
[stderr] I[12:44:35.953] Failed to find compilation database for /home/archer/workspace/test/args_out_of_range.c
[stderr] I[12:44:35.953] ASTWorker building file /home/archer/workspace/test/args_out_of_range.c version 0 with command clangd fallback
[stderr] [/home/archer/workspace/test]
[stderr] /usr/bin/clang -resource-dir=/usr/lib/clang/13.0.1 -- /home/archer/workspace/test/args_out_of_range.c
[stderr] I[12:44:35.973] --> textDocument/publishDiagnostics
[client-request] (id:2) Sat Mar  5 12:44:40 2022:
(:jsonrpc "2.0" :id 2 :method "textDocument/signatureHelp" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 1 :character 0)))
[client-request] (id:3) Sat Mar  5 12:44:40 2022:
(:jsonrpc "2.0" :id 3 :method "textDocument/hover" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 1 :character 0)))
[client-request] (id:4) Sat Mar  5 12:44:40 2022:
(:jsonrpc "2.0" :id 4 :method "textDocument/documentHighlight" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 1 :character 0)))
[server-reply] (id:3) Sat Mar  5 12:44:40 2022:
(:id 3 :jsonrpc "2.0" :result nil)
[server-reply] (id:4) Sat Mar  5 12:44:40 2022:
(:id 4 :jsonrpc "2.0" :result
     [])
[stderr] I[12:44:40.875] <-- textDocument/signatureHelp(2)
[stderr] I[12:44:40.875] <-- textDocument/hover(3)
[stderr] I[12:44:40.876] --> reply:textDocument/hover(3) 0 ms
[stderr] I[12:44:40.876] <-- textDocument/documentHighlight(4)
[stderr] I[12:44:40.876] --> reply:textDocument/documentHighlight(4) 0 ms
[server-reply] (id:2) Sat Mar  5 12:44:40 2022:
(:id 2 :jsonrpc "2.0" :result
     (:activeParameter 0 :activeSignature 0 :signatures
		       []))
[stderr] I[12:44:40.880] --> reply:textDocument/signatureHelp(2) 5 ms
[client-request] (id:5) Sat Mar  5 12:44:41 2022:
(:jsonrpc "2.0" :id 5 :method "textDocument/signatureHelp" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 6 :character 0)))
[client-request] (id:6) Sat Mar  5 12:44:41 2022:
(:jsonrpc "2.0" :id 6 :method "textDocument/hover" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 6 :character 0)))
[client-request] (id:7) Sat Mar  5 12:44:41 2022:
(:jsonrpc "2.0" :id 7 :method "textDocument/documentHighlight" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 6 :character 0)))
[server-reply] (id:6) Sat Mar  5 12:44:41 2022:
(:id 6 :jsonrpc "2.0" :result nil)
[server-reply] (id:7) Sat Mar  5 12:44:41 2022:
(:id 7 :jsonrpc "2.0" :result
     [])
[stderr] I[12:44:41.692] <-- textDocument/signatureHelp(5)
[stderr] I[12:44:41.693] <-- textDocument/hover(6)
[stderr] I[12:44:41.693] --> reply:textDocument/hover(6) 0 ms
[stderr] I[12:44:41.693] <-- textDocument/documentHighlight(7)
[stderr] I[12:44:41.694] --> reply:textDocument/documentHighlight(7) 0 ms
[server-reply] (id:5) Sat Mar  5 12:44:41 2022:
(:id 5 :jsonrpc "2.0" :result
     (:activeParameter 0 :activeSignature 0 :signatures
		       []))
[stderr] I[12:44:41.699] --> reply:textDocument/signatureHelp(5) 6 ms
[client-notification] Sat Mar  5 12:44:42 2022:
(:jsonrpc "2.0" :method "textDocument/didChange" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c" :version 1)
	   :contentChanges
	   [(:range
	     (:start
	      (:line 9 :character 6)
	      :end
	      (:line 9 :character 6))
	     :rangeLength 0 :text ".")]))
[client-request] (id:8) Sat Mar  5 12:44:42 2022:
(:jsonrpc "2.0" :id 8 :method "textDocument/completion" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 9 :character 7)
	   :context
	   (:triggerKind 2 :triggerCharacter ".")))
[stderr] I[12:44:42.975] <-- textDocument/didChange
[stderr] I[12:44:42.975] <-- textDocument/completion(8)
[server-reply] (id:8) Sat Mar  5 12:44:42 2022:
(:id 8 :jsonrpc "2.0" :result
     (:isIncomplete :json-false :items
		    [(:detail "int" :filterText "id" :insertText "id" :insertTextFormat 1 :kind 5 :label " id" :score 1.0192768573760986 :sortText "407d8856id" :textEdit
			      (:newText "id" :range
					(:end
					 (:character 7 :line 9)
					 :start
					 (:character 7 :line 9))))
		     (:detail "char [50]" :filterText "title" :insertText "title" :insertTextFormat 1 :kind 5 :label " title" :score 1.0192768573760986 :sortText "407d8856title" :textEdit
			      (:newText "title" :range
					(:end
					 (:character 7 :line 9)
					 :start
					 (:character 7 :line 9))))]))
[server-notification] Sat Mar  5 12:44:43 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
	  (:diagnostics
	   [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix available)" :range
		   (:end
		    (:character 1 :line 3)
		    :start
		    (:character 0 :line 3))
		   :severity 2 :source "clang")
	    (:code "expected_unqualified_id" :message "Expected identifier" :range
		   (:end
		    (:character 8 :line 10)
		    :start
		    (:character 2 :line 10))
		   :severity 1 :source "clang")]
	   :uri "file:///home/archer/workspace/test/args_out_of_range.c" :version 1))
[stderr] I[12:44:42.979] Code complete: sema context DotMemberAccess, query scopes [] (AnyScope=true), expected type <none>
[stderr] I[12:44:42.980] Code complete: 2 results from Sema, 0 from Index, 0 matched, 0 from identifiers, 2 returned.
[stderr] I[12:44:42.980] --> reply:textDocument/completion(8) 4 ms
[stderr] I[12:44:43.025] Failed to find compilation database for /home/archer/workspace/test/args_out_of_range.c
[stderr] I[12:44:43.025] ASTWorker building file /home/archer/workspace/test/args_out_of_range.c version 1 with command clangd fallback
[stderr] [/home/archer/workspace/test]
[stderr] /usr/bin/clang -resource-dir=/usr/lib/clang/13.0.1 -- /home/archer/workspace/test/args_out_of_range.c
[stderr] I[12:44:43.034] --> textDocument/publishDiagnostics
[client-request] (id:9) Sat Mar  5 12:44:48 2022:
(:jsonrpc "2.0" :id 9 :method "textDocument/signatureHelp" :params
										(:textDocument
											(:uri "file:///home/archer/workspace/test/args_out_of_range.c")
											:position
											(:line 10 :character 11)))
[client-request] (id:10) Sat Mar  5 12:44:48 2022:
(:jsonrpc "2.0" :id 10 :method "textDocument/hover" :params
										(:textDocument
											(:uri "file:///home/archer/workspace/test/args_out_of_range.c")
											:position
											(:line 10 :character 11)))
[client-request] (id:11) Sat Mar  5 12:44:48 2022:
(:jsonrpc "2.0" :id 11 :method "textDocument/documentHighlight" :params
										(:textDocument
											(:uri "file:///home/archer/workspace/test/args_out_of_range.c")
											:position
											(:line 10 :character 11)))
[server-reply] (id:10) Sat Mar  5 12:44:48 2022:
(:id 10 :jsonrpc "2.0" :result nil)
[server-reply] (id:11) Sat Mar  5 12:44:48 2022:
(:id 11 :jsonrpc "2.0" :result
					[])
[stderr] I[12:44:48.811] <-- textDocument/signatureHelp(9)
[stderr] I[12:44:48.811] <-- textDocument/hover(10)
[stderr] I[12:44:48.812] --> reply:textDocument/hover(10) 0 ms
[stderr] I[12:44:48.812] <-- textDocument/documentHighlight(11)
[stderr] I[12:44:48.812] --> reply:textDocument/documentHighlight(11) 0 ms
[server-reply] (id:9) Sat Mar  5 12:44:48 2022:
(:id 9 :jsonrpc "2.0" :result
					(:activeParameter 0 :activeSignature 0 :signatures
																							[]))
[stderr] I[12:44:48.818] --> reply:textDocument/signatureHelp(9) 6 ms
[client-request] (id:12) Sat Mar  5 12:44:55 2022:
(:jsonrpc "2.0" :id 12 :method "textDocument/signatureHelp" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 10 :character 0)))
[client-request] (id:13) Sat Mar  5 12:44:55 2022:
(:jsonrpc "2.0" :id 13 :method "textDocument/hover" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 10 :character 0)))
[client-request] (id:14) Sat Mar  5 12:44:55 2022:
(:jsonrpc "2.0" :id 14 :method "textDocument/documentHighlight" :params
	  (:textDocument
	   (:uri "file:///home/archer/workspace/test/args_out_of_range.c")
	   :position
	   (:line 10 :character 0)))
[server-reply] (id:13) Sat Mar  5 12:44:55 2022:
(:id 13 :jsonrpc "2.0" :result nil)
[server-reply] (id:14) Sat Mar  5 12:44:55 2022:
(:id 14 :jsonrpc "2.0" :result
     [])
[stderr] I[12:44:55.891] <-- textDocument/signatureHelp(12)
[stderr] I[12:44:55.892] <-- textDocument/hover(13)
[stderr] I[12:44:55.892] --> reply:textDocument/hover(13) 0 ms
[stderr] I[12:44:55.892] <-- textDocument/documentHighlight(14)
[stderr] I[12:44:55.893] --> reply:textDocument/documentHighlight(14) 0 ms
[server-reply] (id:12) Sat Mar  5 12:44:55 2022:
(:id 12 :jsonrpc "2.0" :result
     (:activeParameter 0 :activeSignature 0 :signatures
		       []))
[stderr] I[12:44:55.898] --> reply:textDocument/signatureHelp(12) 6 ms

Backtrace (mandatory, unless no error message seen or heard):

Debugger entered--Lisp error: (args-out-of-range #<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)
  funcall(eglot-move-to-lsp-abiding-column 2)
  (let ((tab-width 1) (col (plist-get pos-plist :character))) (if (wholenump col) nil (eglot--warn "Caution: LSP server sent invalid character positio..." col) (setq col 0)) (funcall eglot-move-to-column-function col))
  (if (eobp) nil (let ((tab-width 1) (col (plist-get pos-plist :character))) (if (wholenump col) nil (eglot--warn "Caution: LSP server sent invalid character positio..." col) (setq col 0)) (funcall eglot-move-to-column-function col)))
  (save-restriction (widen) (goto-char (point-min)) (forward-line (min most-positive-fixnum (plist-get pos-plist :line))) (if (eobp) nil (let ((tab-width 1) (col (plist-get pos-plist :character))) (if (wholenump col) nil (eglot--warn "Caution: LSP server sent invalid character positio..." col) (setq col 0)) (funcall eglot-move-to-column-function col))) (if marker (copy-marker (point-marker)) (point)))
  (save-excursion (save-restriction (widen) (goto-char (point-min)) (forward-line (min most-positive-fixnum (plist-get pos-plist :line))) (if (eobp) nil (let ((tab-width 1) (col (plist-get pos-plist :character))) (if (wholenump col) nil (eglot--warn "Caution: LSP server sent invalid character positio..." col) (setq col 0)) (funcall eglot-move-to-column-function col))) (if marker (copy-marker (point-marker)) (point))))
  eglot--lsp-position-to-point((:character 2 :line 8) nil)
  (let* ((st (plist-get range :start)) (beg (eglot--lsp-position-to-point st markers)) (end (eglot--lsp-position-to-point (plist-get range :end) markers))) (cons beg end))
  eglot--range-region((:end (:character 8 :line 8) :start (:character 2 :line 8)))
  (let* ((val (eglot--range-region range))) (progn (ignore (consp val)) (let* ((x16 (car-safe val)) (x17 (cdr-safe val))) (let ((beg x16) (end x17)) (progn (if (= beg end) (progn (let* ... ...))) (eglot--make-diag (current-buffer) beg end (funcall --cl-eglot--diag-type-- severity) message (list (cons ... diag-spec)) (let* (...) (if faces ... nil))))))))
  (progn (eglot--check-object 'Diagnostic object-once (memq 'enforce-required-keys eglot-strict-mode) (memq 'disallow-non-standard-keys eglot-strict-mode) (memq 'check-types eglot-strict-mode)) (setq message (concat source ": " message)) (let* ((val (eglot--range-region range))) (progn (ignore (consp val)) (let* ((x16 (car-safe val)) (x17 (cdr-safe val))) (let ((beg x16) (end x17)) (progn (if (= beg end) (progn ...)) (eglot--make-diag (current-buffer) beg end (funcall --cl-eglot--diag-type-- severity) message (list ...) (let* ... ...))))))))
  (let* ((--cl-rest-- object-once) (range (car (cdr (plist-member --cl-rest-- ':range)))) (message (car (cdr (plist-member --cl-rest-- ':message)))) (severity (car (cdr (plist-member --cl-rest-- ':severity)))) (source (car (cdr (plist-member --cl-rest-- ':source)))) (tags (car (cdr (plist-member --cl-rest-- ':tags))))) (progn (eglot--check-object 'Diagnostic object-once (memq 'enforce-required-keys eglot-strict-mode) (memq 'disallow-non-standard-keys eglot-strict-mode) (memq 'check-types eglot-strict-mode)) (setq message (concat source ": " message)) (let* ((val (eglot--range-region range))) (progn (ignore (consp val)) (let* ((x16 (car-safe val)) (x17 (cdr-safe val))) (let ((beg x16) (end x17)) (progn (if ... ...) (eglot--make-diag ... beg end ... message ... ...))))))))
  (let ((object-once diag-spec)) (let* ((--cl-rest-- object-once) (range (car (cdr (plist-member --cl-rest-- ':range)))) (message (car (cdr (plist-member --cl-rest-- ':message)))) (severity (car (cdr (plist-member --cl-rest-- ':severity)))) (source (car (cdr (plist-member --cl-rest-- ':source)))) (tags (car (cdr (plist-member --cl-rest-- ':tags))))) (progn (eglot--check-object 'Diagnostic object-once (memq 'enforce-required-keys eglot-strict-mode) (memq 'disallow-non-standard-keys eglot-strict-mode) (memq 'check-types eglot-strict-mode)) (setq message (concat source ": " message)) (let* ((val (eglot--range-region range))) (progn (ignore (consp val)) (let* ((x16 ...) (x17 ...)) (let (... ...) (progn ... ...))))))))
  (list (let ((object-once diag-spec)) (let* ((--cl-rest-- object-once) (range (car (cdr (plist-member --cl-rest-- ...)))) (message (car (cdr (plist-member --cl-rest-- ...)))) (severity (car (cdr (plist-member --cl-rest-- ...)))) (source (car (cdr (plist-member --cl-rest-- ...)))) (tags (car (cdr (plist-member --cl-rest-- ...))))) (progn (eglot--check-object 'Diagnostic object-once (memq 'enforce-required-keys eglot-strict-mode) (memq 'disallow-non-standard-keys eglot-strict-mode) (memq 'check-types eglot-strict-mode)) (setq message (concat source ": " message)) (let* ((val (eglot--range-region range))) (progn (ignore (consp val)) (let* (... ...) (let ... ...))))))))
  (nconc diags (list (let ((object-once diag-spec)) (let* ((--cl-rest-- object-once) (range (car (cdr ...))) (message (car (cdr ...))) (severity (car (cdr ...))) (source (car (cdr ...))) (tags (car (cdr ...)))) (progn (eglot--check-object 'Diagnostic object-once (memq 'enforce-required-keys eglot-strict-mode) (memq 'disallow-non-standard-keys eglot-strict-mode) (memq 'check-types eglot-strict-mode)) (setq message (concat source ": " message)) (let* ((val ...)) (progn (ignore ...) (let* ... ...))))))))
  (setq diags (nconc diags (list (let ((object-once diag-spec)) (let* ((--cl-rest-- object-once) (range (car ...)) (message (car ...)) (severity (car ...)) (source (car ...)) (tags (car ...))) (progn (eglot--check-object 'Diagnostic object-once (memq ... eglot-strict-mode) (memq ... eglot-strict-mode) (memq ... eglot-strict-mode)) (setq message (concat source ": " message)) (let* (...) (progn ... ...))))))))
  (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let ((object-once diag-spec)) (let* ((--cl-rest-- object-once) (range ...) (message ...) (severity ...) (source ...) (tags ...)) (progn (eglot--check-object ... object-once ... ... ...) (setq message ...) (let* ... ...))))))))
  (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let ((object-once diag-spec)) (let* (... ... ... ... ... ...) (progn ... ... ...))))))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics (cons t diags)))) nil)
  (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let (...) (let* ... ...)))))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics (cons t diags)))) nil))
  (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let ... ...))))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics (cons t diags)))) nil)) (let* ((path (expand-file-name (eglot--uri-to-path uri))) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let (...) (let* ... ...)))))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil))
  (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list ...)))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics (cons t diags)))) nil)) (let* ((path (expand-file-name (eglot--uri-to-path uri))) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let ... ...))))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil)))
  (progn (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- ...) (< --cl-idx-- ...)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags ...))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics ...))) nil)) (let* ((path (expand-file-name (eglot--uri-to-path uri))) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- (1+ --cl-idx--)) (< --cl-idx-- (length --cl-vec--))) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list ...)))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil))))
  (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond ((null sev) 'eglot-error) ((<= sev 1) 'eglot-error) ((= sev 2) 'eglot-warning) (t 'eglot-note))))) (progn (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and ... ...) (setq diag-spec ...) (setq diags ...)) (cond (eglot--current-flymake-report-fn ...) (t ...)) nil)) (let* ((path (expand-file-name ...)) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and (setq --cl-idx-- ...) (< --cl-idx-- ...)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags ...))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil)))))
  (let* ((uri (car (cdr (plist-member --cl-rest-- ':uri)))) (diagnostics (car (cdr (plist-member --cl-rest-- ':diagnostics))))) (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond (... ...) (... ...) (... ...) (t ...))))) (progn (let* ((buffer (and t (find-buffer-visiting ...)))) (if buffer (save-current-buffer (set-buffer buffer) (let* (... ... ... ...) (while ... ... ...) (cond ... ...) nil)) (let* ((path ...) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (and ... ...) (setq diag-spec ...) (setq diags ...)) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics ...)) (setq flymake-list-only-diagnostics (cons ... flymake-list-only-diagnostics)) nil))))))
  (progn (let* ((uri (car (cdr (plist-member --cl-rest-- ':uri)))) (diagnostics (car (cdr (plist-member --cl-rest-- ':diagnostics))))) (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond ... ... ... ...)))) (progn (let* ((buffer (and t ...))) (if buffer (save-current-buffer (set-buffer buffer) (let* ... ... ... nil)) (let* (... ... ... ... ...) (while ... ... ...) (setq flymake-list-only-diagnostics ...) (setq flymake-list-only-diagnostics ...) nil)))))))
  (closure (revert-buffer-preserve-modes eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (_server _method &rest --cl-rest--) "Handle notification publishDiagnostics.\n\n(fn SERVE..." (progn (let* ((uri (car (cdr ...))) (diagnostics (car (cdr ...)))) (let* ((--cl-eglot--diag-type-- #'...)) (progn (let* (...) (if buffer ... ...)))))))(#<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> textDocument/publishDiagnostics :diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27)
  apply((closure (revert-buffer-preserve-modes eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (_server _method &rest --cl-rest--) "Handle notification publishDiagnostics.\n\n(fn SERVE..." (progn (let* ((uri (car (cdr ...))) (diagnostics (car (cdr ...)))) (let* ((--cl-eglot--diag-type-- #'...)) (progn (let* (...) (if buffer ... ...))))))) #<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> textDocument/publishDiagnostics (:diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27))
  eglot-handle-notification(#<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> textDocument/publishDiagnostics :diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27)
  apply(eglot-handle-notification #<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> textDocument/publishDiagnostics (:diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27))
  (let ((eglot--cached-server server)) (apply fn server method (append params nil)))
  (closure ((fn . eglot-handle-notification) (initargs :process (closure ((contact "/usr/bin/clangd") (server-info "/usr/bin/clangd") (autostart-inferior-process) (readable-name . "EGLOT (test/c-mode)") (nickname . "test") (language-id . "c") (contact "/usr/bin/clangd") (class . eglot-lsp-server) (project transient . "/home/archer/workspace/test/") (managed-major-mode . c-mode) eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) nil (let ((default-directory default-directory)) (make-process :name readable-name :command (setq server-info ...) :connection-type 'pipe :coding 'utf-8-emacs-unix :noquery t :stderr (get-buffer-create ...) :file-handler t)))) (contact "/usr/bin/clangd") (server-info "/usr/bin/clangd") (autostart-inferior-process) (readable-name . "EGLOT (test/c-mode)") (nickname . "test") (language-id . "c") (contact "/usr/bin/clangd") (class . eglot-lsp-server) (project transient . "/home/archer/workspace/test/") (managed-major-mode . c-mode) eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (server method params) (let ((eglot--cached-server server)) (apply fn server method (append params nil))))(#<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> textDocument/publishDiagnostics (:diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27))
  jsonrpc-connection-receive(#<eglot-lsp-server eglot-lsp-server-15727e2d7d0e> (:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params (:diagnostics [(:code "ext_expected_semi_decl_list" :message "Expected ';' at end of declaration list (fix avail..." :range (:end (:character 1 :line 3) :start (:character 0 :line 3)) :severity 2 :source "clang") (:code "expected_unqualified_id" :message "Expected identifier" :range (:end (:character 8 :line 8) :start (:character 2 :line 8)) :severity 1 :source "clang")] :uri "file:///home/archer/workspace/test/args_out_of_ran..." :version 27)))
  jsonrpc--process-filter(#<process EGLOT (test/c-mode)> "Content-Length: 545\15\n\15\n{\"jsonrpc\":\"2.0\",\"method\":\"...")

Minimal configuration (mandatory)

# Type this in a shell to start an Emacs with Eglot configured
$ emacs -Q -l eglot-start.el
;;; eglot-start.el
(require 'package)

(setq debug-on-error t
     no-byte-compile t
     byte-compile-warnings nil
     inhibit-startup-screen t
     package-archives '(("melpa" . "https://melpa.org/packages/")
                        ("gnu" . "https://elpa.gnu.org/packages/"))
     package-user-dir (make-temp-file "eglot-tmp-elpa")
     custom-file (expand-file-name "custom.el" package-user-dir))

(delete-file package-user-dir)

(let* ((pkg-list '(eglot company)))

 (package-initialize)
 (package-refresh-contents)

 (mapc (lambda (pkg)
         (unless (package-installed-p pkg)
           (package-install pkg))
         (require pkg))
       pkg-list)
 (global-company-mode 1)

 (add-hook 'c-mode-hook 'eglot-ensure)
 (add-hook 'kill-emacs-hook `(lambda ()
                               (delete-directory ,package-user-dir t))))

(provide 'eglot-start)
// args_out_of_range.c
struct Book {
  int id;
  char title[50]
} book = { 1024, "C" };

int main(int argc, char *argv[])
{

  // Error when typing "book."
  book
  return 0;
}
@drshapeless
Copy link

I am having a similar issue with you. I also use clangd version 13.0.1. Eglot version d03235f.

The error message is something like this.

error in process filter: eglot-move-to-lsp-abiding-column: Args out of range: #<buffer main.cc>, 125, 139
error in process filter: Args out of range: #<buffer main.cc>, 125, 139

I tried to dig a bit into the eglot-move-to-lsp-abiding-column function, but not finding anything useful.

This only affect clangd.

@drshapeless
Copy link

Can confirm this is not just a bug in eglot, but a bug in the latest build of Emacs, which is 29.0.50. If you pull the origin/emacs-28 branch and build that, no more Args out of range pop up.
My current Emacs version is 28.0.91.

A few extra information is that, this bug is probably not related to configuring --with-x-input2 flag, since I have build Emacs with and without this flag and the issue persists.

I have been using Emacs 29.0.50 for a couple of months and the issue just arise in the recent week or two. Maybe the master branch of Emacs introduce some new features or bug fixes that breaks eglot. But I have not been able to track which specifically causes the issue.

From my observation, the Args out of range issue only happens with clangd and ccls is my use cases. I have yet to see other language servers raise the same issue.

@joaotavora
Copy link
Owner

Thanks. This looks like a well-described bug. Will try to look at this later today.

@joaotavora joaotavora added the bug label Mar 9, 2022
@nemethf
Copy link
Collaborator

nemethf commented Mar 9, 2022

Based on the descriptions above and the fact that Eglot's CI started to fail 16 days ago, I'm guessing this commit causes the trouble: emacs-mirror/emacs@a8245e1

I might be totally wrong here, but can you, @drshapeless, build an emacs without that commit, and check it the bug persists? (Or if I guessed wrong, can you git-bisect the commit that started to cause the issue?) Thanks.

@drshapeless
Copy link

drshapeless commented Mar 10, 2022

Based on the descriptions above and the fact that Eglot's CI started to fail 16 days ago, I'm guessing this commit causes the trouble: emacs-mirror/emacs@a8245e1

I might be totally wrong here, but can you, @drshapeless, build an emacs without that commit, and check it the bug persists? (Or if I guessed wrong, can you git-bisect the commit that started to cause the issue?) Thanks.

I have just built Emacs with commit prior than a8245e1, but the issue persists. The commit was 4 weeks old, a bit older than what I would expect. I remember pulling and building the latest Emacs by the end of February, and had no issues at all. (I may be wrong on the time though.) This is weird.

What I would guess is some new features in emacs29 causing the issue, especially the xinput2 and pixel-scrolling-precision related commits.

I am trying to locate the commit. But I don't have a lot of free time until weekend.

A new discovery is that with company-mode disabled, no errors. The real bug may not be in Emacs itself. But some weird interactions new Emacs and packages.

@nemethf
Copy link
Collaborator

nemethf commented Mar 10, 2022

I have just built Emacs with commit prior than a8245e1, but the issue persists.

Bummer.

I am trying to locate the commit. But I don't have a lot of free time until weekend.

There's no need to hurry.

I'm guessing the automated tests on github failed because of this issue, so a scripted git-bisect using make eglot-check would find the problematic commit without user interaction. Although, it might not be worth the trouble to write that script, I don't know.

@joaotavora
Copy link
Owner

I think a git bisect is in order, doesn't have to be fully scripted, I think. One thing that could speed it up is trying to reduce the test case to a simpler one. I've tried to eval (encode-coding-region 110 124 'utf-16 t) , the form that presumably throws the error, interactively in a args_out_of_range.c buffer. But I don't get the error in either 27.2 or a recent-ish Emacs from Feb 23.

@joaotavora
Copy link
Owner

I cannot reproduce this. Here's my recipe. I use your args_out_of_range.c file.

❯ clangd --version
clangd version 13.0.1
Features: linux
Platform: x86_64-pc-linux-gnu
❯ ~/Source/Emacs/emacs/src/emacs --version
GNU Emacs 29.0.50
Copyright (C) 2022 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
❯ git log -1
commit b90d2f39259c9f6e7ec4cd964f3608a52a0f335b (HEAD -> master, origin/master, origin/HEAD)
Author: João Távora <joaotavora@gmail.com>
Date:   Fri Mar 11 13:05:03 2022 +0000

    Unbreak CI tests, use new jtdls for Eclipse JDT (per #863, #864, #868)

    * .github/workflows/test.yml (Install Python): tweak Python version
    (Install Eclipse JDT): Tweak $GITHUB_PATH

    * eglot-tests.el (eclipse-workspace-folders): Remove.
    (eglot--have-eclipse-jdt-ls-p): Remove.
    (eclipse-connect): Simplify.
❯ git -C ~/Source/Emacs/emacs log -1
commit 88d474308e2a0b4a6cac2714135f6bbcae689ed4 (HEAD -> master, origin/master, origin/HEAD)
Author: Po Lu <luangruo@yahoo.com>
Date:   Fri Mar 11 08:56:54 2022 +0000

    Fix inconsistent thumb position on Haiku scroll bars

    * src/haikuterm.c (haiku_set_scroll_bar_thumb): If
    scroll_bar_adjust_thumb_portion is nil, directly calculate thumb
    portions without setting page_size.
❯ ~/Source/Emacs/emacs/src/emacs -Q -L . -l eglot ~/tmp/issue-860/args_out_of_range.c -f eglot

Everything works fine, and I type "book" and I don't get an error.

Please clarify exactly what steps trigger the error.

@vdcow
Copy link

vdcow commented Mar 11, 2022

@joaotavora
Sometimes, first autocomplete works for me as well but I could consistently reproduce this issue using the following sequence

  1. Type
book.id = 45
  1. Remove typed characters up to the "book" and try to trigger autocompletion again.

@joaotavora
Copy link
Owner

OK, I can reproduce this, but only with company-mode. For reference:

~/Source/Emacs/emacs/src/emacs -Q -L . -L ~/Source/Emacs/company-mode -l company -f global-company-mode -l eglot ~/tmp/issue-860/args_out_of_range.c -f eglot

nemethf added a commit that referenced this issue Mar 12, 2022
I thought the server must reply with a subset of the client's list of
codeActionKind during the initialization.  But it's clearly not the case.
The typescript-language-server returns these [1]:

  ["source.fixAll.ts" "source.removeUnused.ts" "source.addMissingImports.ts" ...]

The clangd server returns these [2]:

  ["quickfix" "refactor" "info"]

(Additionally, in the current code there is a mismatch between what
Eglot initially sent and the completing read arguemnt of
eglot-code-actions.  "source" and "refactor" is missing from
`eglot-code-actions'. Was this intentional?)

Now, Eglot plays safe, and offers the union of the two lists as
possible completions in `eglot-code-actions'.

[1]: #847 (comment)
[2]: #860
@trev-dev
Copy link

I was also having this problem, but I chose to re-think my configuration. I ended up switching to vertico, corfu & cape. I get my completions from Eglot via LSP, no problems now.

This doesn't resolve this issue, but it is a way out of it. Vertico/Corfu implement the same completion philosophy as Eglot by using supported internals.

@drshapeless
Copy link

@trev-dev That was a good approach. It kind of confirms that the root of the problem is about newer emacs and company-mode. A side benefit of switching to corfu is that, the performance slightly improve.

@joaotavora
Copy link
Owner

That was a good approach. It kind of confirms that the root of the problem is about newer emacs and company-mode.

Normally, i would agree with you, since that's where the evidence points to, but from the backtrace, i think the problem is more likely in Eglot itself and a problematic implementation of eglot-lsp-abiding-column. Though maybe it doesn't hurt to hail company-mode's developer, @dgutov, here for some insight into why that package is needed to reproduce this.

@dgutov
Copy link
Collaborator

dgutov commented Mar 17, 2022

If some of your code depends on the visual column, or characters being "visible", it could conflict with the default overlay-based popup.

Using a frontend which is based on child frames (which Corfu is one example of) should fix that, with the obvious downside of not being able to work in a terminal.

@trev-dev
Copy link

Using a frontend which is based on child frames (which Corfu is one example of) should fix that, with the obvious downside of not being able to work in a terminal.

I hadn't thought of this! Vertico takes an out-of-the-way approach to solving this kind of problem. Vertico being made by the same developer as Corfu/Cape. For myself I am not sure if proactive auto-completion is a thing I truly need, or if I truly need it at point, but we're getting much more off-track if I'm allowed to keep babbling about alternatives.

https://github.com/minad/vertico#completion-at-point-and-completion-in-region

I wonder why child frames are so attractive. The only time I've ever had a performance problem while moving my point as been due to something trying to make a child frame.

@joaotavora
Copy link
Owner

If some of your code depends on the visual column, or characters being "visible", it could conflict with the default overlay-based popup.

Right, this is more or less my thinking too. But in theory, no, Eglot does not depend on "visible" characters, not that I know of. Does company momentarily insert characters for making its overlay technique?

@dgutov
Copy link
Collaborator

dgutov commented Mar 18, 2022

I wonder why child frames are so attractive. The only time I've ever had a performance problem while moving my point as been due to something trying to make a child frame.

Child frames indeed have some performance problems, but that's also dependent on the desktop environment in use (I hear they are more prominent under GNOME Shell than under XFCE, for example), but there are a number of optimizations possible which are included in libs such as posframe. With further improvement worked on, I think.

Though of course it would be better to have "native" popups with more optimal performance. Someday.

Right, this is more or less my thinking too. But in theory, no, Eglot does not depend on "visible" characters, not that I know of. Does company momentarily insert characters for making its overlay technique?

It used to insert a newline when at eob a number of years ago, but not anymore. So no.

But the overlay property invisible affects functions such as current-column, for example.

@joaotavora
Copy link
Owner

It used to insert a newline when at eob a number of years ago, but not anymore. So no.

Interesting. I think yasnippet still does that, I'll check how company solved it later.

But the overlay property invisible affects functions such as current-column, for example.

Ah, that must be it. Eglot does use current column indeed. Thanks for this hint.

but we're getting much more off-track if I'm allowed to keep babbling about alternatives.

@trev-dev babbling is very much allowed as I do it all the time :), but it could be nice to move this discussion about completion elsewhere (and keep me in the loop, as I have some input there, too)

@joaotavora
Copy link
Owner

But the overlay property invisible affects functions such as current-column, for example.
Ah, that must be it. Eglot does use current column indeed. Thanks for this hint.

Actually, no :-) Eglot doesn't use current-column. It used to, but not anymore. But it uses similar stuff which I suppose can be affected in the same way. line-beginning-position maybe.

There's also the fact that Eglot and some old-ish company works fine in Emacs 27.2, but not in current master. Even probably in Emacs 28. So there must have been some regression in Emacs. If you've been following Emacs stuff more closely than I have, then any hint would also be appreciated.

Anyway, I can reproduce the problem reliably now, so I should be back with more info soon.

@joaotavora
Copy link
Owner

Yup, so this is the deal. Eglot uses move-to-column to do the "abiding LSP column dance".

In Emacs 27.2, move-to-column is unaffected by previous company-mode overlays, even if the current line is being co-used visually by the overlay. It moves to the right buffer position.

In Emacs master, this isn't true. It seems to be confounded by the company-mode overlay and moves to eob, which breaks Eglot.

Eglot breaks with the latter. I think a defensive fix is in order in Eglot, but this is clearly a regression in Emacs. Pretty please, who has the time/patience to M-x report-emacs-bug? 🙏

@joaotavora
Copy link
Owner

Alright, I think I pushed a decent defensive fix, though it doesn't seem to be an Eglot bug . The commit message of that commit has everything to make a decent bug report, I think. I just don't know if this is an Emacs of company-mode bug. @dgutov may have a relevant opinion.

Here is the commit message text, for convenience, in case someone wants to copy-paste to a bug report:

commit f77518711507810b779d87190d0ca0183fc02e10
Author: João Távora <joaotavora@gmail.com>
Date:   Fri Mar 18 10:54:21 2022 +0000

    Fix #860: Defend against broken move-to-column in recent Emacs
    
    * eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))
    
    This is a defensive fix for an Emacs/company-mode problem described
    below.
    
    The problem can be reproduced in Eglot before this commit with:
    
    ~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
    ~/Source/Emacs/company-mode -l company -f global-company-mode -l \
     eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
     display-line-numbers-mode -f toggle-debug-on-error
    
      1 // args_out_of_range.c
      2 struct Book {
      3   int id;
      4   char title[50]
      5 } book = { 1024, "C" };
      6
      7 int main(int argc, char *argv[])
      8 {
      9
     10   // Error when typing the dot to make "book."
     11   book
     12   return 0;
     13 }
    
    When one types the dot after the "book" on line 11, company-mode
    displays a two-line overlay that visually encompasses line 12 after
    "book", which has the "return 0;" statement.  That line happens to
    also hold a warning about incorrect syntax, one that starts at column
    2.
    
    Eglot uses 'move-to-column' to go that precise place.
    
    In Emacs 27.2, move-to-column is unaffected by previous company-mode
    overlays, even if the current line is being co-used visually by the
    overlay.  It moves to the right buffer position.
    
    In Emacs master, this isn't true.  It seems to be confounded by the
    company-mode overlay and moves to eob, which eventually breaks Eglot
    with a backtrace such as this one:
    
    Debugger entered--Lisp error: (args-out-of-range #<buffer args_out_of_range.c> 110 124)
      encode-coding-region(110 124 utf-16 t)
      (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
      (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
      (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
      eglot-lsp-abiding-column(110)
      (- column (eglot-lsp-abiding-column lbp))
      (setq diff (- column (eglot-lsp-abiding-column lbp)))
      (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
      (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
      (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
      (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
      (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
      eglot-move-to-lsp-abiding-column(2)

diff --git a/eglot.el b/eglot.el
index ea9299a..3bd2d84 100644
--- a/eglot.el
+++ b/eglot.el
@@ -1312,7 +1312,8 @@ fully LSP-compliant servers, this should be set to
   "Calculate current COLUMN as defined by the LSP spec.
 LBP defaults to `line-beginning-position'."
   (/ (- (length (encode-coding-region (or lbp (line-beginning-position))
-                                      (point) 'utf-16 t))
+                                      ;; Fix github#860
+                                      (min (point) (point-max)) 'utf-16 t))
         2)
      2))

@dgutov
Copy link
Collaborator

dgutov commented Mar 18, 2022

Please go ahead with the bug report. As I recall, you have a much higher opinion of Debbugs than myself, so it should be natural for you to do this.

The scenario should also be easy enough to reproduce without Company, just with a multi-line (?) overlay and the invisible property. Maybe even overlay being multiline is not necessary.

The behavior does sound like a regression, that seems like enough of a justification for me.

@joaotavora
Copy link
Owner

As I recall, you have a much higher opinion of Debbugs than myself, so it should be natural for you to do this.

It's just email :-) And I ended up writing the error report in the commit message anyway.

The scenario should also be easy enough to reproduce without Company, just with a multi-line (?) overlay and the invisible property. Maybe even overlay being multiline is not necessary.

If you can type up that simpler recipe you're envisioning, that'd be very nice indeed, and I'll be happy to attach it to my email. I don't have time, so the current company-specific one it will have to be.

The behavior does sound like a regression, that seems like enough of a justification for me.

Let's see what people say over at the bug tracker. The current solution is minimally less performant for Eglot, since the bisection algorithm has to search a larger space, but I haven't measured but I wouldn't say much.

@dgutov
Copy link
Collaborator

dgutov commented Mar 19, 2022

If you can type up that simpler recipe you're envisioning, that'd be very nice indeed, and I'll be happy to attach it to my email. I don't have time, so the current company-specific one it will have to be.

Fine by me.

You'd have to do the recipe anyway because you know which kind of code has to misbehave with it. I only suggested circumstances as a rough guess, but step one would be to verify the problem in those circumstances.

@joaotavora
Copy link
Owner

You'd have to do the recipe anyway because you know which kind of code has to misbehave with it.

So do you :-) It's current-column and move-to-column and you guessed :-)

@dgutov
Copy link
Collaborator

dgutov commented Mar 19, 2022

Again, I'm not sure about your assumptions.

(insert "aaaabbbb\nccccdddd")
(setq o (make-overlay 10 14))
(overlay-put o 'invisible t)
(move-to-column 4)

Is that misbehavior?

@dgutov
Copy link
Collaborator

dgutov commented Mar 19, 2022

I'm not seeing the difference in behavior between 29 and 27 here.

@joaotavora
Copy link
Owner

Is that misbehavior?

If it doesn't do the same on Emacs master than it did on 27.2, yes. Else no.

@dgutov
Copy link
Collaborator

dgutov commented Mar 19, 2022

OK, let's see how the bug report fares.

@joaotavora
Copy link
Owner

I'm not seeing the difference in behavior between 29 and 27 here.

So you're not seeing the regression then, and a slightly more complex recipe needs to be tried.

@joaotavora
Copy link
Owner

Eglot does a narrowing to the line trying to move to column, maybe that matters.

bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 18, 2022
…ent Emacs

* eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))

This is a defensive fix for an Emacs/company-mode problem described
below.

The problem can be reproduced in Eglot before this commit with:

~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
~/Source/Emacs/company-mode -l company -f global-company-mode -l \
 eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
 display-line-numbers-mode -f toggle-debug-on-error

  1 // args_out_of_range.c
  2 struct Book {
  3   int id;
  4   char title[50]
  5 } book = { 1024, "C" };
  6
  7 int main(int argc, char *argv[])
  8 {
  9
 10   // Error when typing the dot to make "book."
 11   book
 12   return 0;
 13 }

When one types the dot after the "book" on line 11, company-mode
displays a two-line overlay that visually encompasses line 12 after
"book", which has the "return 0;" statement.  That line happens to
also hold a warning about incorrect syntax, one that starts at column
2.

Eglot uses 'move-to-column' to go that precise place.

In Emacs 27.2, move-to-column is unaffected by previous company-mode
overlays, even if the current line is being co-used visually by the
overlay.  It moves to the right buffer position.

In Emacs master, this isn't true.  It seems to be confounded by the
company-mode overlay and moves to eob, which eventually breaks Eglot
with a backtrace such as this one:

Debugger entered--Lisp error: (args-out-of-range https://github.com/joaotavora/eglot/issues/<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
…ent Emacs

* eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))

This is a defensive fix for an Emacs/company-mode problem described
below.

The problem can be reproduced in Eglot before this commit with:

~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
~/Source/Emacs/company-mode -l company -f global-company-mode -l \
 eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
 display-line-numbers-mode -f toggle-debug-on-error

  1 // args_out_of_range.c
  2 struct Book {
  3   int id;
  4   char title[50]
  5 } book = { 1024, "C" };
  6
  7 int main(int argc, char *argv[])
  8 {
  9
 10   // Error when typing the dot to make "book."
 11   book
 12   return 0;
 13 }

When one types the dot after the "book" on line 11, company-mode
displays a two-line overlay that visually encompasses line 12 after
"book", which has the "return 0;" statement.  That line happens to
also hold a warning about incorrect syntax, one that starts at column
2.

Eglot uses 'move-to-column' to go that precise place.

In Emacs 27.2, move-to-column is unaffected by previous company-mode
overlays, even if the current line is being co-used visually by the
overlay.  It moves to the right buffer position.

In Emacs master, this isn't true.  It seems to be confounded by the
company-mode overlay and moves to eob, which eventually breaks Eglot
with a backtrace such as this one:

Debugger entered--Lisp error: (args-out-of-range https://github.com/joaotavora/eglot/issues/<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)
bhankas pushed a commit to bhankas/emacs that referenced this issue Sep 19, 2022
* eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))

This is a defensive fix for an Emacs/company-mode problem described
below.

The problem can be reproduced in Eglot before this commit with:

~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
~/Source/Emacs/company-mode -l company -f global-company-mode -l \
 eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
 display-line-numbers-mode -f toggle-debug-on-error

  1 // args_out_of_range.c
  2 struct Book {
  3   int id;
  4   char title[50]
  5 } book = { 1024, "C" };
  6
  7 int main(int argc, char *argv[])
  8 {
  9
 10   // Error when typing the dot to make "book."
 11   book
 12   return 0;
 13 }

When one types the dot after the "book" on line 11, company-mode
displays a two-line overlay that visually encompasses line 12 after
"book", which has the "return 0;" statement.  That line happens to
also hold a warning about incorrect syntax, one that starts at column
2.

Eglot uses 'move-to-column' to go that precise place.

In Emacs 27.2, move-to-column is unaffected by previous company-mode
overlays, even if the current line is being co-used visually by the
overlay.  It moves to the right buffer position.

In Emacs master, this isn't true.  It seems to be confounded by the
company-mode overlay and moves to eob, which eventually breaks Eglot
with a backtrace such as this one:

Debugger entered--Lisp error: (args-out-of-range #<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)

#860: joaotavora/eglot#860
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 12, 2022
* eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))

This is a defensive fix for an Emacs/company-mode problem described
below.

The problem can be reproduced in Eglot before this commit with:

~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
~/Source/Emacs/company-mode -l company -f global-company-mode -l \
 eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
 display-line-numbers-mode -f toggle-debug-on-error

  1 // args_out_of_range.c
  2 struct Book {
  3   int id;
  4   char title[50]
  5 } book = { 1024, "C" };
  6
  7 int main(int argc, char *argv[])
  8 {
  9
 10   // Error when typing the dot to make "book."
 11   book
 12   return 0;
 13 }

When one types the dot after the "book" on line 11, company-mode
displays a two-line overlay that visually encompasses line 12 after
"book", which has the "return 0;" statement.  That line happens to
also hold a warning about incorrect syntax, one that starts at column
2.

Eglot uses 'move-to-column' to go that precise place.

In Emacs 27.2, move-to-column is unaffected by previous company-mode
overlays, even if the current line is being co-used visually by the
overlay.  It moves to the right buffer position.

In Emacs master, this isn't true.  It seems to be confounded by the
company-mode overlay and moves to eob, which eventually breaks Eglot
with a backtrace such as this one:

Debugger entered--Lisp error: (args-out-of-range #<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)

GitHub-reference: fix joaotavora/eglot#860
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this issue Oct 20, 2022
* eglot.el (eglot-lsp-abiding-column): Use (min (point) (point-max))

This is a defensive fix for an Emacs/company-mode problem described
below.

The problem can be reproduced in Eglot before this commit with:

~/Source/Emacs/emacs/src/emacs -Q -f package-initialize -L       \
~/Source/Emacs/company-mode -l company -f global-company-mode -l \
 eglot.el ~/tmp/issue-860/args_out_of_range.c -f eglot -f        \
 display-line-numbers-mode -f toggle-debug-on-error

  1 // args_out_of_range.c
  2 struct Book {
  3   int id;
  4   char title[50]
  5 } book = { 1024, "C" };
  6
  7 int main(int argc, char *argv[])
  8 {
  9
 10   // Error when typing the dot to make "book."
 11   book
 12   return 0;
 13 }

When one types the dot after the "book" on line 11, company-mode
displays a two-line overlay that visually encompasses line 12 after
"book", which has the "return 0;" statement.  That line happens to
also hold a warning about incorrect syntax, one that starts at column
2.

Eglot uses 'move-to-column' to go that precise place.

In Emacs 27.2, move-to-column is unaffected by previous company-mode
overlays, even if the current line is being co-used visually by the
overlay.  It moves to the right buffer position.

In Emacs master, this isn't true.  It seems to be confounded by the
company-mode overlay and moves to eob, which eventually breaks Eglot
with a backtrace such as this one:

Debugger entered--Lisp error: (args-out-of-range #<buffer args_out_of_range.c> 110 124)
  encode-coding-region(110 124 utf-16 t)
  (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t))
  (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2)
  (/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (point) 'utf-16 t)) 2) 2)
  eglot-lsp-abiding-column(110)
  (- column (eglot-lsp-abiding-column lbp))
  (setq diff (- column (eglot-lsp-abiding-column lbp)))
  (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff)))
  (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil))
  (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)
  (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil))
  (save-restriction (catch '--cl-block-nil-- (let* ((lbp (line-beginning-position)) (diff nil) (--cl-var-- t)) (narrow-to-region lbp (line-end-position)) (move-to-column column) (while (progn (setq diff (- column (eglot-lsp-abiding-column lbp))) (not (= 0 diff))) (condition-case eob-err (forward-char (/ (if ... ... ...) 2)) (end-of-buffer (throw '--cl-block-nil-- eob-err))) (setq --cl-var-- nil)) nil)))
  eglot-move-to-lsp-abiding-column(2)

GitHub-reference: fix joaotavora/eglot#860
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants