Commit a5774ba7 authored by Fangrui Song's avatar Fangrui Song

Inauguration of emacs-ccls

It is a long story behind my decision to rename. But today is Good Friday.
parent 383656d3
[![MELPA](https://melpa.org/packages/cquery-badge.svg)](https://melpa.org/#/cquery)
# emacs-ccls
# emacs-cquery
emacs-ccls is a client for [ccls](https://github.com/MaskRay/ccls), a C/C++/Objective-C language server supporting multi-million line C++ code-bases, powered by libclang.
emacs-cquery is a client for [cquery](https://github.com/jacobdufault/cquery), a low-latency language server supporting multi-million line C++ code-bases, powered by libclang.
It leverages [lsp-mode](https://github.com/emacs-lsp/lsp-mode), but also provides some cquery extensions to LSP:
It leverages [lsp-mode](https://github.com/emacs-lsp/lsp-mode), but also provides some ccls extensions to LSP:
* semantic highlighting
* inactive region (e.g. a `#if false` region)
* cross references: `$cquery/base` `$cquery/callers` `$cquery/derived` `$cquery/vars`
* cross references: `$ccls/base` `$ccls/callers` `$ccls/derived` `$ccls/vars`
More on <https://github.com/cquery-project/cquery/wiki/Emacs>
More on <https://github.com/MaskRay/ccls/wiki/Emacs>
## Quickstart
```elisp
(require 'cquery)
(setq cquery-executable "/path/to/cquery/build/release/bin/cquery")
;; (setq cquery-executable "/path/to/cquery-install-prefix/bin/cquery")
(require 'ccls)
(setq ccls-executable "/path/to/ccls/release/ccls")
```
To enable comments and use Message Pack for cache files (which are stored in `cacheDirectory`):
```elisp
(setq cquery-extra-init-params '(:index (:comments 2) :cacheFormat "msgpack"))
(setq ccls-extra-init-params '(:cacheFormat "msgpack"))
```
Refer to <https://github.com/jacobdufault/cquery/wiki/Emacs> for details.
Refer to <https://github.com/MaskRay/ccls/wiki/Emacs> for details.
![with lsp-ui-doc, enableComments](https://camo.githubusercontent.com/fe1e12f9be72c2295d732d6265b42bde0d121ee8/68747470733a2f2f707470622e70772f5a6275462e6a7067)
![references + hydra](https://ptpb.pw/fhWh.jpg)
![with company-lsp](https://ptpb.pw/lDaw.jpg)
![with helm-xref, approximate workspace/symbol search](https://ptpb.pw/KOKn.jpg)
`$cquery/memberHierarchy`
![$cquery/memberHierarchy](https://ptpb.pw/iOSt.gif)
`$ccls/memberHierarchy`
![$ccls/memberHierarchy](https://ptpb.pw/iOSt.gif)
`$cquery/callHierarchy` (caller hierarchy and callee hierarchy)
![$cquery/callHierarchy](https://ptpb.pw/GKJw.gif)
`$ccls/callHierarchy` (caller hierarchy and callee hierarchy)
![$ccls/callHierarchy](https://ptpb.pw/GKJw.gif)
## License
......
;;; -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Tobias Pisani
;; Copyright (C) 2018 Fangrui Song
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
......@@ -22,117 +23,117 @@
;;; Code:
(require 'cquery-common)
(require 'cquery-tree)
(require 'ccls-common)
(require 'ccls-tree)
;; ---------------------------------------------------------------------
;; Customization
;; ---------------------------------------------------------------------
(defface cquery-call-hierarchy-node-normal-face
(defface ccls-call-hierarchy-node-normal-face
nil
"."
:group 'cquery)
:group 'ccls)
(defface cquery-call-hierarchy-node-base-face
(defface ccls-call-hierarchy-node-base-face
'((t (:foreground "orange red")))
"."
:group 'cquery)
:group 'ccls)
(defface cquery-call-hierarchy-node-derived-face
(defface ccls-call-hierarchy-node-derived-face
'((t (:foreground "orange")))
"."
:group 'cquery)
:group 'ccls)
(defcustom cquery-call-hierarchy-use-detailed-name nil
(defcustom ccls-call-hierarchy-use-detailed-name nil
"Use detailed name for call hierarchy"
:group 'cquery
:group 'ccls
:type 'boolean)
;; ---------------------------------------------------------------------
;; Tree node
;; ---------------------------------------------------------------------
(cl-defstruct cquery-call-hierarchy-node
(cl-defstruct ccls-call-hierarchy-node
id
name
call-type)
(defun cquery-call-hierarchy--read-node (data &optional parent)
(defun ccls-call-hierarchy--read-node (data &optional parent)
"Construct a call tree node from hashmap DATA and give it the parent PARENT"
(-let* ((location (gethash "location" data))
(filename (lsp--uri-to-path (gethash "uri" location)))
((&hash "id" id "name" name "callType" call-type) data))
(make-cquery-tree-node
(make-ccls-tree-node
:location (cons filename (gethash "start" (gethash "range" location)))
:has-children (< 0 (gethash "numChildren" data))
:parent parent
:expanded nil
:children nil
:data (make-cquery-call-hierarchy-node
:data (make-ccls-call-hierarchy-node
:id id
:name name
:call-type call-type))))
(defun cquery-call-hierarchy--request-children (callee node)
(defun ccls-call-hierarchy--request-children (callee node)
"."
(let ((id (cquery-call-hierarchy-node-id (cquery-tree-node-data node))))
(--map (cquery-call-hierarchy--read-node it node)
(let ((id (ccls-call-hierarchy-node-id (ccls-tree-node-data node))))
(--map (ccls-call-hierarchy--read-node it node)
(gethash "children"
(lsp--send-request
(lsp--make-request "$cquery/callHierarchy"
(lsp--make-request "$ccls/callHierarchy"
`(:id ,id
:callee ,callee
:callType 3
:levels ,cquery-tree-initial-levels
:detailedName ,(if cquery-call-hierarchy-use-detailed-name t :json-false)
:levels ,ccls-tree-initial-levels
:detailedName ,(if ccls-call-hierarchy-use-detailed-name t :json-false)
)))))))
(defun cquery-call-hierarchy--request-init (callee)
(defun ccls-call-hierarchy--request-init (callee)
"."
(cquery--cquery-buffer-check)
(ccls--ccls-buffer-check)
(lsp--send-request
(lsp--make-request "$cquery/callHierarchy"
(lsp--make-request "$ccls/callHierarchy"
`(:textDocument (:uri ,(concat lsp--uri-file-prefix buffer-file-name))
:position ,(lsp--cur-position)
:callee ,callee
:callType 3
:detailedName ,(if cquery-call-hierarchy-use-detailed-name t :json-false)
:detailedName ,(if ccls-call-hierarchy-use-detailed-name t :json-false)
))))
(defun cquery-call-hierarchy--make-string (node depth)
(defun ccls-call-hierarchy--make-string (node depth)
"Propertize the name of NODE with the correct properties"
(let ((data (cquery-tree-node-data node)))
(let ((data (ccls-tree-node-data node)))
(if (= depth 0)
(cquery-call-hierarchy-node-name data)
(ccls-call-hierarchy-node-name data)
(concat
(propertize (cquery-call-hierarchy-node-name data)
'face (pcase (cquery-call-hierarchy-node-call-type data)
('0 'cquery-call-hierarchy-node-normal-face)
('1 'cquery-call-hierarchy-node-base-face)
('2 'cquery-call-hierarchy-node-derived-face)))
(propertize (ccls-call-hierarchy-node-name data)
'face (pcase (ccls-call-hierarchy-node-call-type data)
('0 'ccls-call-hierarchy-node-normal-face)
('1 'ccls-call-hierarchy-node-base-face)
('2 'ccls-call-hierarchy-node-derived-face)))
(propertize (format " (%s:%s)"
(file-name-nondirectory (car (cquery-tree-node-location node)))
(gethash "line" (cdr (cquery-tree-node-location node))))
'face 'cquery-mode-line-face)))))
(file-name-nondirectory (car (ccls-tree-node-location node)))
(gethash "line" (cdr (ccls-tree-node-location node))))
'face 'ccls-mode-line-face)))))
(defun cquery-call-hierarchy (callee)
(defun ccls-call-hierarchy (callee)
(interactive "P")
(cquery--cquery-buffer-check)
(ccls--ccls-buffer-check)
(setq callee (if callee t :json-false))
(cquery-tree--open
(make-cquery-tree-client
(ccls-tree--open
(make-ccls-tree-client
:name "call hierarchy"
:mode-line-format (format " %s %s %s %s"
(propertize (if (eq callee t) "Callee types:" "Caller types:") 'face 'cquery-tree-mode-line-face)
(propertize "Normal" 'face 'cquery-call-hierarchy-node-normal-face)
(propertize "Base" 'face 'cquery-call-hierarchy-node-base-face)
(propertize "Derived" 'face 'cquery-call-hierarchy-node-derived-face))
:top-line-f (lambda () (propertize (if (eq callee t) "Callees of " "Callers of") 'face 'cquery-tree-mode-line-face))
:make-string-f 'cquery-call-hierarchy--make-string
:read-node-f 'cquery-call-hierarchy--read-node
:request-children-f (apply-partially #'cquery-call-hierarchy--request-children callee)
:request-init-f (lambda () (cquery-call-hierarchy--request-init callee)))))
(provide 'cquery-call-hierarchy)
;;; cquery-call-hierarchy.el ends here
(propertize (if (eq callee t) "Callee types:" "Caller types:") 'face 'ccls-tree-mode-line-face)
(propertize "Normal" 'face 'ccls-call-hierarchy-node-normal-face)
(propertize "Base" 'face 'ccls-call-hierarchy-node-base-face)
(propertize "Derived" 'face 'ccls-call-hierarchy-node-derived-face))
:top-line-f (lambda () (propertize (if (eq callee t) "Callees of " "Callers of") 'face 'ccls-tree-mode-line-face))
:make-string-f 'ccls-call-hierarchy--make-string
:read-node-f 'ccls-call-hierarchy--read-node
:request-children-f (apply-partially #'ccls-call-hierarchy--request-children callee)
:request-init-f (lambda () (ccls-call-hierarchy--request-init callee)))))
(provide 'ccls-call-hierarchy)
;;; ccls-call-hierarchy.el ends here
;;; -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Tobias Pisani
;; Copyright (C) 2018 Fangrui Song
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
......@@ -22,28 +23,28 @@
;;; Code:
(require 'cquery-common)
(require 'ccls-common)
(defgroup cquery-code-lens nil
"cquery code lens."
(defgroup ccls-code-lens nil
"ccls code lens."
:group 'tools
:group 'cquery)
:group 'ccls)
(defface cquery-code-lens-face
(defface ccls-code-lens-face
'((t :inherit shadow))
"The face used for code lens overlays."
:group 'cquery-code-lens)
:group 'ccls-code-lens)
(defface cquery-code-lens-mouse-face
(defface ccls-code-lens-mouse-face
'((t :box t))
"The face used for code lens overlays."
:group 'cquery-code-lens)
:group 'ccls-code-lens)
;; ---------------------------------------------------------------------
;; Codelens
;;
;; Enable by calling `cquery-request-code-lens'
;; Clear them away using `cquery-clear-code-lens'
;; Enable by calling `ccls-request-code-lens'
;; Clear them away using `ccls-clear-code-lens'
;;
;; TODO:
;; - Find a better way to display them.
......@@ -55,22 +56,22 @@
;; - Add a global option to request code lenses on automatically
;; ---------------------------------------------------------------------
(defun cquery--make-code-lens-string (command)
(defun ccls--make-code-lens-string (command)
"."
(let ((map (make-sparse-keymap)))
(define-key map [mouse-1] (lambda () (interactive) (cquery--execute-command (gethash "command" command) (gethash "arguments" command))))
(define-key map [mouse-1] (lambda () (interactive) (ccls--execute-command (gethash "command" command) (gethash "arguments" command))))
(propertize (gethash "title" command)
'face 'cquery-code-lens-face
'mouse-face 'cquery-code-lens-mouse-face
'face 'ccls-code-lens-face
'mouse-face 'ccls-code-lens-mouse-face
'local-map map)))
(defun cquery--code-lens-callback (result)
(defun ccls--code-lens-callback (result)
"."
(overlay-recenter (point-max))
(cquery-clear-code-lens)
(ccls-clear-code-lens)
(let (buffers)
(dolist (lens result)
(let* ((range (cquery--read-range (gethash "range" lens)))
(let* ((range (ccls--read-range (gethash "range" lens)))
(root (gethash "command" lens))
;; (title (gethash "title" root))
;; (command (gethash "command" root))
......@@ -79,44 +80,44 @@
(with-current-buffer buffer
(save-excursion
(when (not (member buffer buffers))
(cquery-clear-code-lens)
(ccls-clear-code-lens)
(overlay-recenter (point-max))
(setq buffers (cons buffer buffers)))
(let ((ov (make-overlay (car range) (cdr range) buffer)))
(overlay-put ov 'cquery-code-lens t)
(overlay-put ov 'after-string (format " %s" (cquery--make-code-lens-string root)))))))))))
(overlay-put ov 'ccls-code-lens t)
(overlay-put ov 'after-string (format " %s" (ccls--make-code-lens-string root)))))))))))
(defun cquery-request-code-lens ()
"Request code lens from cquery."
(defun ccls-request-code-lens ()
"Request code lens from ccls."
(interactive)
(lsp--cur-workspace-check)
(lsp--send-request-async
(lsp--make-request "textDocument/codeLens"
`(:textDocument (:uri ,(concat lsp--uri-file-prefix buffer-file-name))))
'cquery--code-lens-callback))
'ccls--code-lens-callback))
(defun cquery-clear-code-lens ()
(defun ccls-clear-code-lens ()
"Clear all code lenses from this buffer."
(interactive)
(dolist (ov (overlays-in (point-min) (point-max)))
(when (overlay-get ov 'cquery-code-lens)
(when (overlay-get ov 'ccls-code-lens)
(delete-overlay ov))))
(defun cquery-code-lens--request-when-idle ()
(run-with-idle-timer 0.5 nil 'cquery-request-code-lens))
(defun ccls-code-lens--request-when-idle ()
(run-with-idle-timer 0.5 nil 'ccls-request-code-lens))
(define-minor-mode cquery-code-lens-mode
(define-minor-mode ccls-code-lens-mode
"toggle code-lens overlays"
:group 'cquery
:group 'ccls
:global nil
:init-value nil
:lighter "Lens"
(pcase cquery-code-lens-mode
(pcase ccls-code-lens-mode
('t
(cquery-request-code-lens)
(add-hook 'lsp-after-diagnostics-hook 'cquery-code-lens--request-when-idle t t))
(ccls-request-code-lens)
(add-hook 'lsp-after-diagnostics-hook 'ccls-code-lens--request-when-idle t t))
('nil
(remove-hook 'lsp-after-diagnostics-hook 'cquery-code-lens--request-when-idle t)
(cquery-clear-code-lens))))
(remove-hook 'lsp-after-diagnostics-hook 'ccls-code-lens--request-when-idle t)
(ccls-clear-code-lens))))
(provide 'cquery-code-lens)
(provide 'ccls-code-lens)
;;; -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Tobias Pisani
;; Copyright (C) 2018 Fangrui Song
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
......@@ -32,50 +33,50 @@
;; Customization
;; ---------------------------------------------------------------------
(defgroup cquery nil
"Customization options for the cquery client"
(defgroup ccls nil
"Customization options for the ccls client"
:group 'tools)
;; ---------------------------------------------------------------------
;; Utility
;; ---------------------------------------------------------------------
(defun cquery--read-range (range)
(defun ccls--read-range (range)
(cons (lsp--position-to-point (gethash "start" range))
(lsp--position-to-point (gethash "end" range))))
(defsubst cquery--root-from-file (file)
(defsubst ccls--root-from-file (file)
(-when-let (match (locate-dominating-file default-directory file))
(expand-file-name match)))
(defsubst cquery--root-from-func (func)
(defsubst ccls--root-from-func (func)
(and (fboundp func) (ignore-errors (funcall func))))
(cl-defun cquery-project-roots-matcher ()
(cl-loop for root in cquery-project-roots do
(cl-defun ccls-project-roots-matcher ()
(cl-loop for root in ccls-project-roots do
(when (string-prefix-p (expand-file-name root) buffer-file-name)
(cl-return-from cquery--get-root root))))
(cl-return-from ccls--get-root root))))
(cl-defun cquery--get-root ()
"Return the root directory of a cquery project."
(cl-loop for matcher in cquery-project-root-matchers do
(cl-defun ccls--get-root ()
"Return the root directory of a ccls project."
(cl-loop for matcher in ccls-project-root-matchers do
(-when-let (root (cl-typecase matcher
(string (cquery--root-from-file matcher))
(function (cquery--root-from-func matcher))))
(cl-return-from cquery--get-root root)))
(user-error "Could not find cquery project root"))
(string (ccls--root-from-file matcher))
(function (ccls--root-from-func matcher))))
(cl-return-from ccls--get-root root)))
(user-error "Could not find ccls project root"))
(defun cquery--is-cquery-buffer (&optional buffer)
"Return non-nil if current buffer is using the cquery client"
(defun ccls--is-ccls-buffer (&optional buffer)
"Return non-nil if current buffer is using the ccls client"
(with-current-buffer (or buffer (current-buffer))
(and lsp--cur-workspace
(eq (lsp--client-get-root (lsp--workspace-client lsp--cur-workspace)) 'cquery--get-root))))
(eq (lsp--client-get-root (lsp--workspace-client lsp--cur-workspace)) 'ccls--get-root))))
(define-inline cquery--cquery-buffer-check ()
(inline-quote (cl-assert (cquery--is-cquery-buffer) nil
"Cquery is not enabled in this buffer.")))
(define-inline ccls--ccls-buffer-check ()
(inline-quote (cl-assert (ccls--is-ccls-buffer) nil
"ccls is not enabled in this buffer.")))
(defun cquery--get-renderer ()
(defun ccls--get-renderer ()
(thread-last lsp--cur-workspace
lsp--workspace-client
lsp--client-string-renderers
......@@ -85,19 +86,19 @@
(funcall (current-buffer))))
cdr))
(defun cquery--render-string (str)
(funcall (cquery--get-renderer) str))
(defun ccls--render-string (str)
(funcall (ccls--get-renderer) str))
(defun cquery--render-type (str)
(defun ccls--render-type (str)
"Render a string as a type"
(string-remove-suffix " a;" (cquery--render-string (format "%s a;" str))))
(string-remove-suffix " a;" (ccls--render-string (format "%s a;" str))))
;; ---------------------------------------------------------------------
;; Notification handlers
;; ---------------------------------------------------------------------
(defvar cquery--handlers
'(("$cquery/progress" . (lambda (_w _p))))
(defvar ccls--handlers
'(("$ccls/progress" . (lambda (_w _p))))
"List of cons-cells of (METHOD . HANDLER) pairs, where METHOD is the lsp method to handle,
and handler is a function invoked as (handler WORKSPACE PARAMS), where WORKSPACE is the current
lsp-workspace, and PARAMS is a hashmap of the params recieved with the notification.")
......@@ -106,32 +107,32 @@ lsp-workspace, and PARAMS is a hashmap of the params recieved with the notificat
;; Commands
;; ---------------------------------------------------------------------
(defun cquery--execute-command (command &optional arguments)
"Execute a cquery command."
(defun ccls--execute-command (command &optional arguments)
"Execute a ccls command."
(let* ((uri (car arguments))
(data (cdr arguments)))
(save-current-buffer
(find-file (lsp--uri-to-path uri))
(pcase command
;; Code actions
('"cquery._applyFixIt"
('"ccls._applyFixIt"
(dolist (edit data)
(cquery--apply-textedit (car edit))))
('"cquery._autoImplement"
(ccls--apply-textedit (car edit))))
('"ccls._autoImplement"
(dolist (edit data)
(cquery--apply-textedit (car edit)))
(ccls--apply-textedit (car edit)))
(goto-char (lsp--position-to-point
(gethash "start" (gethash "range" (caar data))))))
('"cquery._insertInclude"
(cquery--select-textedit data "Include: "))
('"cquery.showReferences" ;; Used by code lenses
('"ccls._insertInclude"
(ccls--select-textedit data "Include: "))
('"ccls.showReferences" ;; Used by code lenses
(xref--show-xrefs (lsp--locations-to-xref-items (cadr data)) nil))
(_
(message "unknown command: %s" command))))))
(defun cquery--select-textedit (edit-list prompt)
(defun ccls--select-textedit (edit-list prompt)
"Show a list of possible textedits, and apply the selected.
Used by cquery._insertInclude"
Used by ccls._insertInclude"
(let ((name-func (lambda (edit)
(concat (lsp--position-to-point
(gethash "start" (gethash "range" edit)))
......@@ -146,9 +147,9 @@ lsp-workspace, and PARAMS is a hashmap of the params recieved with the notificat
(cl-loop
for edit in edit-list
do (when (equal (funcall name-func edit) str)
(cquery--apply-textedit edit)))))))
(ccls--apply-textedit edit)))))))
(defun cquery--apply-textedit (edit)
(defun ccls--apply-textedit (edit)
(let* ((range (gethash "range" edit))
(start (lsp--position-to-point (gethash "start" range)))
(end (lsp--position-to-point (gethash "end" range)))
......@@ -158,13 +159,12 @@ lsp-workspace, and PARAMS is a hashmap of the params recieved with the notificat
(goto-char start)
(insert newText)))
(defun cquery--execute-command-locally-advice (orig-func command args)
"Cquery currently doesn't support `workspace/executeCommand', so execute those locally.
Keep an eye on https://github.com/jacobdufault/cquery/issues/283"
(if (cquery--is-cquery-buffer)
(cquery--execute-command command args)
(defun ccls--execute-command-locally-advice (orig-func command args)
"ccls currently doesn't support `workspace/executeCommand', so execute those locally."
(if (ccls--is-ccls-buffer)
(ccls--execute-command command args)
(funcall orig-func args)))
(advice-add 'lsp--send-execute-command :around #'cquery--execute-command-locally-advice)
(advice-add 'lsp--send-execute-command :around #'ccls--execute-command-locally-advice)
(provide 'cquery-common)
(provide 'ccls-common)
;;; -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Tobias Pisani
;; Copyright (C) 2018 Fangrui Song
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
......@@ -22,96 +23,96 @@
;;; Code:
(require 'cquery-common)
(require 'cquery-tree)
(require 'ccls-common)
(require 'ccls-tree)
(defface cquery-inheritance-hierarchy-base-face
(defface ccls-inheritance-hierarchy-base-face
'((t (:foreground "orange red")))
"."
:group 'cquery)
:group 'ccls)
(defcustom cquery-inheritance-hierarchy-use-detailed-name t
(defcustom ccls-inheritance-hierarchy-use-detailed-name t
"Use detailed name for types in inheritance hierarchy"
:group 'cquery
:group 'ccls
:type 'boolean)
(cl-defstruct cquery-inheritance-hierarchy-node
(cl-defstruct ccls-inheritance-hierarchy-node
id
kind
name)
(defun cquery-inheritance-hierarchy--read-node (data &optional parent)
(defun ccls-inheritance-hierarchy--read-node (data &optional parent)
"Construct a call tree node from hashmap DATA and give it the parent PARENT"
(-let* ((location (gethash "location" data '(nil . nil)))
(filename (lsp--uri-to-path (gethash "uri" location)))
((&hash "id" id "kind" kind "name" name) data)
(node
(make-cquery-tree-node
(make-ccls-tree-node
:location (cons filename (gethash "start" (gethash "range" location)))
:has-children (< 0 (gethash "numChildren" data))
:parent parent
:expanded nil
:children nil
:data (make-cquery-inheritance-hierarchy-node
:data (make-ccls-inheritance-hierarchy-node
:id id
:kind kind
:name name))))
(setf (cquery-tree-node-children node)
(--map (cquery-inheritance-hierarchy--read-node it node)
(setf (ccls-tree-node-children node)
(--map (ccls-inheritance-hierarchy--read-node it node)
(gethash "children" data)))
node))
(defun cquery-inheritance-hierarchy--request-children (derived node)
(defun ccls-inheritance-hierarchy--request-children (derived node)
"."
(let ((id (cquery-inheritance-hierarchy-node-id (cquery-tree-node-data node)))
(kind (cquery-inheritance-hierarchy-node-kind (cquery-tree-node-data node))))
(--map (cquery-inheritance-hierarchy--read-node it node)
(let ((id (ccls-inheritance-hierarchy-node-id (ccls-tree-node-data node)))
(kind (ccls-inheritance-hierarchy-node-kind (ccls-tree-node-data node))))
(--map (ccls-inheritance-hierarchy--read-node it node)
(gethash "children"
(lsp--send-request
(lsp--make-request "$cquery/inheritanceHierarchy"
(lsp--make-request "$ccls/inheritanceHierarchy"
`(:id ,id :kind ,kind
:derived ,derived
:detailedName ,(if cquery-inheritance-hierarchy-use-detailed-name t :json-false)
:levels ,cquery-tree-initial-levels)))))))
:detailedName ,(if ccls-inheritance-hierarchy-use-detailed-name t :json-false)
:levels ,ccls-tree-initial-levels)))))))
(defun cquery-inheritance-hierarchy--request-init (derived)
(defun ccls-inheritance-hierarchy--request-init (derived)
"."
(cquery--cquery-buffer-check)
(ccls--ccls-buffer-check)
(lsp--send-request
(lsp--make-request "$cquery/inheritanceHierarchy"
(lsp--make-request "$ccls/inheritanceHierarchy"
`(
:textDocument (:uri ,(concat lsp--uri-file-prefix buffer-file-name))
:position ,(lsp--cur-position)
:derived ,derived
:detailedName ,(if cquery-inheritance-hierarchy-use-detailed-name t :json-false)
:detailedName ,(if ccls-inheritance-hierarchy-use-detailed-name t :json-false)
:levels 1))))
(defun cquery-inheritance-hierarchy--make-string (node _depth)
(defun ccls-inheritance-hierarchy--make-string (node _depth)
"Propertize the name of NODE with the correct properties"
(let* ((data (cquery-tree-node-data node))
(name (cquery-inheritance-hierarchy-node-name data)))
(let* ((data (ccls-tree-node-data node))
(name (ccls-inheritance-hierarchy-node-name data)))
(if (string-equal name "[[Base]]")
(propertize "Bases" 'face 'cquery-inheritance-hierarchy-base-face)
(cquery--render-type name))))
(propertize "Bases" 'face 'ccls-inheritance-hierarchy-base-face)
(ccls--render-type name))))
(defun cquery-inheritance-hierarchy (derived)
(defun ccls-inheritance-hierarchy (derived)
(interactive "P")
(cquery--cquery-buffer-check)
(ccls--ccls-buffer-check)
(let ((json-derived (if derived t :json-false)))
(cquery-tree--open
(make-cquery-tree-client
(ccls-tree--open
(make-ccls-tree-client
:name "inheritance hierarchy"
:mode-line-format (propertize (if derived
"Inheritance Hierarchy: Subclasses"
"Inheritance Hierarchy: Bases")
'face 'cquery-tree-mode-line-face)
:top-line-f (lambda () (propertize (if derived "Derive from" "Bases of") 'face 'cquery-tree-mode-line-face))
:make-string-f 'cquery-inheritance-hierarchy--make-string
:read-node-f 'cquery-inheritance-hierarchy--read-node
:request-children-f (apply-partially #'cquery-inheritance-hierarchy--request-children json-derived)
:request-init-f (lambda () (cquery-inheritance-hierarchy--request-init json-derived))))))
(provide 'cquery-inheritance-hierarchy)
;;; cquery-inheritance-hierarchy.el ends here
'face 'ccls-tree-mode-line-face)
:top-line-f (lambda () (propertize (if derived "Derive from" "Bases of") 'face 'ccls-tree-mode-line-face))
:make-string-f 'ccls-inheritance-hierarchy--make-string
:read-node-f 'ccls-inheritance-hierarchy--read-node
:request-children-f (apply-partially #'ccls-inheritance-hierarchy--request-children json-derived)
:request-init-f (lambda () (ccls-inheritance-hierarchy--request-init json-derived))))))
(provide 'ccls-inheritance-hierarchy)
;;; ccls-inheritance-hierarchy.el ends here
;;; -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Tobias Pisani
;; Copyright (C) 2018 Fangrui Song
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
......@@ -22,86 +23,86 @@
;;; Code:
(require 'cquery-common)
(require 'cquery-tree)
(require 'ccls-common)
(require 'ccls-tree)
(defcustom cquery-member-hierarchy-use-detailed-name t
(defcustom ccls-member-hierarchy-use-detailed-name t
"Use detailed name for member hierarchy"
:group 'cquery
:group 'ccls
:type 'boolean)
;; ---------------------------------------------------------------------
;; Tree node
;; ---------------------------------------------------------------------
(cl-defstruct cquery-member-hierarchy-node
(cl-defstruct ccls-member-hierarchy-node
name
field-name
id)
(