mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Report document links on includes
This commit is contained in:
		
							parent
							
								
									41e1dff4c9
								
							
						
					
					
						commit
						7a79532fff
					
				@ -28,7 +28,7 @@ be productive with cquery. Here's a list of implemented features:
 | 
				
			|||||||
  * diagnostics
 | 
					  * diagnostics
 | 
				
			||||||
  * code actions (clang FixIts)
 | 
					  * code actions (clang FixIts)
 | 
				
			||||||
  * darken/fade code disabled by preprocessor
 | 
					  * darken/fade code disabled by preprocessor
 | 
				
			||||||
  * goto definition on include to jump to file
 | 
					  * goto definition, document links on include to jump to file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Setup - build cquery, install extension, setup project
 | 
					# Setup - build cquery, install extension, setup project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -914,6 +914,7 @@ void RegisterMessageTypes() {
 | 
				
			|||||||
  MessageRegistry::instance()->Register<Ipc_TextDocumentHover>();
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentHover>();
 | 
				
			||||||
  MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>();
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>();
 | 
				
			||||||
  MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>();
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>();
 | 
				
			||||||
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentLink>();
 | 
				
			||||||
  MessageRegistry::instance()->Register<Ipc_TextDocumentCodeAction>();
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentCodeAction>();
 | 
				
			||||||
  MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>();
 | 
					  MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>();
 | 
				
			||||||
  MessageRegistry::instance()->Register<Ipc_CodeLensResolve>();
 | 
					  MessageRegistry::instance()->Register<Ipc_CodeLensResolve>();
 | 
				
			||||||
@ -1539,6 +1540,9 @@ bool QueryDbMainLoop(
 | 
				
			|||||||
        response.result.capabilities.documentSymbolProvider = true;
 | 
					        response.result.capabilities.documentSymbolProvider = true;
 | 
				
			||||||
        response.result.capabilities.workspaceSymbolProvider = true;
 | 
					        response.result.capabilities.workspaceSymbolProvider = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response.result.capabilities.documentLinkProvider = lsDocumentLinkOptions();
 | 
				
			||||||
 | 
					        response.result.capabilities.documentLinkProvider->resolveProvider = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ipc->SendOutMessageToClient(IpcId::Initialize, response);
 | 
					        ipc->SendOutMessageToClient(IpcId::Initialize, response);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -2097,6 +2101,68 @@ bool QueryDbMainLoop(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case IpcId::TextDocumentDocumentLink: {
 | 
				
			||||||
 | 
					        auto msg = static_cast<Ipc_TextDocumentDocumentLink*>(message.get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Out_TextDocumentDocumentLink response;
 | 
				
			||||||
 | 
					        response.id = msg->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (config->showDocumentLinksOnIncludes) {
 | 
				
			||||||
 | 
					          QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath());
 | 
				
			||||||
 | 
					          if (!file) {
 | 
				
			||||||
 | 
					            std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          WorkingFile* working_file = working_files->GetFileByFilename(msg->params.textDocument.uri.GetPath());
 | 
				
			||||||
 | 
					          if (!working_file) {
 | 
				
			||||||
 | 
					            std::cerr << "Unable to find working file " << msg->params.textDocument.uri.GetPath() << std::endl;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          for (const IndexInclude& include : file->def.includes) {
 | 
				
			||||||
 | 
					            optional<int> buffer_line;
 | 
				
			||||||
 | 
					            optional<std::string> buffer_line_content = working_file->GetBufferLineContentFromIndexLine(include.line, &buffer_line);
 | 
				
			||||||
 | 
					            if (!buffer_line || !buffer_line_content)
 | 
				
			||||||
 | 
					              continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Find starting and ending quote.
 | 
				
			||||||
 | 
					            int start = 0;
 | 
				
			||||||
 | 
					            while (start < buffer_line_content->size()) {
 | 
				
			||||||
 | 
					              char c = (*buffer_line_content)[start];
 | 
				
			||||||
 | 
					              ++start;
 | 
				
			||||||
 | 
					              if (c == '"' || c == '<')
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (start == buffer_line_content->size())
 | 
				
			||||||
 | 
					              continue;
 | 
				
			||||||
 | 
					            int end = buffer_line_content->size();
 | 
				
			||||||
 | 
					            while (end > 0) {
 | 
				
			||||||
 | 
					              char c = (*buffer_line_content)[end];
 | 
				
			||||||
 | 
					              if (c == '"' || c == '>')
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              --end;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (start >= end)
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lsDocumentLink link;
 | 
				
			||||||
 | 
					            link.target = lsDocumentUri::FromPath(include.resolved_path);
 | 
				
			||||||
 | 
					            // Subtract 1 from line because querydb stores 1-based lines but
 | 
				
			||||||
 | 
					            // vscode expects 0-based lines.
 | 
				
			||||||
 | 
					            link.range.start.line = *buffer_line - 1;
 | 
				
			||||||
 | 
					            link.range.start.character = start;
 | 
				
			||||||
 | 
					            link.range.end.line = *buffer_line - 1;
 | 
				
			||||||
 | 
					            link.range.end.character = end;
 | 
				
			||||||
 | 
					            response.result.push_back(link);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response.Write(std::cerr);
 | 
				
			||||||
 | 
					        ipc->SendOutMessageToClient(IpcId::TextDocumentDocumentLink, response);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      case IpcId::TextDocumentCodeAction: {
 | 
					      case IpcId::TextDocumentCodeAction: {
 | 
				
			||||||
        // NOTE: This code snippet will generate some FixIts for testing:
 | 
					        // NOTE: This code snippet will generate some FixIts for testing:
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
@ -2495,6 +2561,7 @@ void LanguageServerStdinLoop(IndexerConfig* config, std::unordered_map<IpcId, Ti
 | 
				
			|||||||
    case IpcId::TextDocumentHover:
 | 
					    case IpcId::TextDocumentHover:
 | 
				
			||||||
    case IpcId::TextDocumentReferences:
 | 
					    case IpcId::TextDocumentReferences:
 | 
				
			||||||
    case IpcId::TextDocumentDocumentSymbol:
 | 
					    case IpcId::TextDocumentDocumentSymbol:
 | 
				
			||||||
 | 
					    case IpcId::TextDocumentDocumentLink:
 | 
				
			||||||
    case IpcId::TextDocumentCodeAction:
 | 
					    case IpcId::TextDocumentCodeAction:
 | 
				
			||||||
    case IpcId::TextDocumentCodeLens:
 | 
					    case IpcId::TextDocumentCodeLens:
 | 
				
			||||||
    case IpcId::WorkspaceSymbol:
 | 
					    case IpcId::WorkspaceSymbol:
 | 
				
			||||||
 | 
				
			|||||||
@ -38,6 +38,8 @@ const char* IpcIdToString(IpcId id) {
 | 
				
			|||||||
    return "textDocument/references";
 | 
					    return "textDocument/references";
 | 
				
			||||||
  case IpcId::TextDocumentDocumentSymbol:
 | 
					  case IpcId::TextDocumentDocumentSymbol:
 | 
				
			||||||
    return "textDocument/documentSymbol";
 | 
					    return "textDocument/documentSymbol";
 | 
				
			||||||
 | 
					  case IpcId::TextDocumentDocumentLink:
 | 
				
			||||||
 | 
					    return "textDocument/documentLink";
 | 
				
			||||||
  case IpcId::TextDocumentCodeAction:
 | 
					  case IpcId::TextDocumentCodeAction:
 | 
				
			||||||
    return "textDocument/codeAction";
 | 
					    return "textDocument/codeAction";
 | 
				
			||||||
  case IpcId::TextDocumentCodeLens:
 | 
					  case IpcId::TextDocumentCodeLens:
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@ enum class IpcId : int {
 | 
				
			|||||||
  TextDocumentHover,
 | 
					  TextDocumentHover,
 | 
				
			||||||
  TextDocumentReferences,
 | 
					  TextDocumentReferences,
 | 
				
			||||||
  TextDocumentDocumentSymbol,
 | 
					  TextDocumentDocumentSymbol,
 | 
				
			||||||
 | 
					  TextDocumentDocumentLink,
 | 
				
			||||||
  TextDocumentCodeAction,
 | 
					  TextDocumentCodeAction,
 | 
				
			||||||
  TextDocumentCodeLens,
 | 
					  TextDocumentCodeLens,
 | 
				
			||||||
  CodeLensResolve,
 | 
					  CodeLensResolve,
 | 
				
			||||||
 | 
				
			|||||||
@ -74,6 +74,9 @@ struct IndexerConfig {
 | 
				
			|||||||
  // If false, the index will not be loaded from a previous run.
 | 
					  // If false, the index will not be loaded from a previous run.
 | 
				
			||||||
  bool enableCacheRead = true;
 | 
					  bool enableCacheRead = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If true, document links are reported for #include directives.
 | 
				
			||||||
 | 
					  bool showDocumentLinksOnIncludes = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Enables code lens on parameter and function variables.
 | 
					  // Enables code lens on parameter and function variables.
 | 
				
			||||||
  bool codeLensOnLocalVariables = true;
 | 
					  bool codeLensOnLocalVariables = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,6 +92,8 @@ MAKE_REFLECT_STRUCT(IndexerConfig,
 | 
				
			|||||||
  indexerCount,
 | 
					  indexerCount,
 | 
				
			||||||
  enableIndexing, enableCacheWrite, enableCacheRead,
 | 
					  enableIndexing, enableCacheWrite, enableCacheRead,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  showDocumentLinksOnIncludes,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  codeLensOnLocalVariables,
 | 
					  codeLensOnLocalVariables,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  clientVersion);
 | 
					  clientVersion);
 | 
				
			||||||
@ -1492,6 +1497,36 @@ struct Out_TextDocumentDocumentSymbol : public lsOutMessage<Out_TextDocumentDocu
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
 | 
					MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// List links a document
 | 
				
			||||||
 | 
					struct Ipc_TextDocumentDocumentLink : public IpcMessage<Ipc_TextDocumentDocumentLink> {
 | 
				
			||||||
 | 
					  const static IpcId kIpcId = IpcId::TextDocumentDocumentLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct DocumentLinkParams {
 | 
				
			||||||
 | 
					    // The document to provide document links for.
 | 
				
			||||||
 | 
					    lsTextDocumentIdentifier textDocument;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lsRequestId id;
 | 
				
			||||||
 | 
					  DocumentLinkParams params;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink::DocumentLinkParams, textDocument);
 | 
				
			||||||
 | 
					MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink, id, params);
 | 
				
			||||||
 | 
					// A document link is a range in a text document that links to an internal or external resource, like another
 | 
				
			||||||
 | 
					// text document or a web site.
 | 
				
			||||||
 | 
					struct lsDocumentLink {
 | 
				
			||||||
 | 
						// The range this link applies to.
 | 
				
			||||||
 | 
						lsRange range;
 | 
				
			||||||
 | 
						// The uri this link points to. If missing a resolve request is sent later.
 | 
				
			||||||
 | 
						optional<lsDocumentUri> target;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MAKE_REFLECT_STRUCT(lsDocumentLink, range, target);
 | 
				
			||||||
 | 
					struct Out_TextDocumentDocumentLink : public lsOutMessage<Out_TextDocumentDocumentLink> {
 | 
				
			||||||
 | 
					  lsRequestId id;
 | 
				
			||||||
 | 
					  NonElidedVector<lsDocumentLink> result;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentLink, jsonrpc, id, result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List code lens in a document.
 | 
					// List code lens in a document.
 | 
				
			||||||
struct lsDocumentCodeLensParams {
 | 
					struct lsDocumentCodeLensParams {
 | 
				
			||||||
  lsTextDocumentIdentifier textDocument;
 | 
					  lsTextDocumentIdentifier textDocument;
 | 
				
			||||||
 | 
				
			|||||||
@ -164,6 +164,22 @@ optional<int> WorkingFile::GetIndexLineFromBufferLine(int buffer_line) const {
 | 
				
			|||||||
  return closest_index_line;
 | 
					  return closest_index_line;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					optional<std::string> WorkingFile::GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const {
 | 
				
			||||||
 | 
					  optional<int> buffer_line = GetBufferLineFromIndexLine(indexed_line);
 | 
				
			||||||
 | 
					  if (out_buffer_line)
 | 
				
			||||||
 | 
					    *out_buffer_line = buffer_line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!buffer_line)
 | 
				
			||||||
 | 
					    return nullopt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (*buffer_line < 1 || *buffer_line >= all_buffer_lines.size()) {
 | 
				
			||||||
 | 
					    std::cerr << "GetBufferLineContentFromIndexLine buffer line lookup not in all_buffer_lines" << std::endl;
 | 
				
			||||||
 | 
					    return nullopt;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return all_buffer_lines[*buffer_line - 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* active_parameter, lsPosition* completion_position) const {
 | 
					std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* active_parameter, lsPosition* completion_position) const {
 | 
				
			||||||
  *active_parameter = 0;
 | 
					  *active_parameter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -44,6 +44,8 @@ struct WorkingFile {
 | 
				
			|||||||
  // accepts and returns 1-based lines.
 | 
					  // accepts and returns 1-based lines.
 | 
				
			||||||
  optional<int> GetIndexLineFromBufferLine(int buffer_line) const;
 | 
					  optional<int> GetIndexLineFromBufferLine(int buffer_line) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  optional<std::string> GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Finds the closest 'callable' name prior to position. This is used for
 | 
					  // Finds the closest 'callable' name prior to position. This is used for
 | 
				
			||||||
  // signature help to filter code completion results.
 | 
					  // signature help to filter code completion results.
 | 
				
			||||||
  //
 | 
					  //
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user