pkg_check_modules(CMARK_GFM REQUIRED IMPORTED_TARGET libcmark-gfm) pkg_check_modules(TREE_SITTER REQUIRED IMPORTED_TARGET tree-sitter) find_path(JKQTPlotter6_CMAKE_DIR NAMES JKQTMathText6Config.cmake HINTS /usr/lib/cmake/JKQTPlotter6 /usr/local/lib/cmake/JKQTPlotter6 DOC "Directory containing the JKQtPlotter cmake package files") find_package(JKQTMathText6 REQUIRED PATHS "${JKQTPlotter6_CMAKE_DIR}") function(_ts_entry_point out file) get_filename_component(_ts_nm_base "${file}" NAME) set(_ts_nm_file "${CMAKE_CURRENT_BINARY_DIR}/ts-entry-${_ts_nm_base}") execute_process( COMMAND nm -D --defined-only "${file}" RESULT_VARIABLE _ts_nm_rc OUTPUT_FILE "${_ts_nm_file}" ERROR_FILE "${_ts_nm_file}.err") set(_ts_sym "tree_sitter_missing") if(_ts_nm_rc EQUAL 0 AND EXISTS "${_ts_nm_file}") file(READ "${_ts_nm_file}" _ts_nm_out) file(REMOVE "${_ts_nm_file}" "${_ts_nm_file}.err") string(REGEX MATCHALL " T tree_sitter_[A-Za-z0-9_]+" _ts_syms "${_ts_nm_out}") foreach(_ts_s IN LISTS _ts_syms) string(REPLACE " T " "" _ts_s "${_ts_s}") if(NOT _ts_s MATCHES "_external") set(_ts_sym "${_ts_s}") break() endif() endforeach() endif() set(${out} "${_ts_sym}" PARENT_SCOPE) endfunction() function(_ts_expand_inherits query_dir text outVar) set(result "${text}") set(_visited "") set(_depth 0) while(_depth LESS 8) string(REGEX MATCHALL "inherits:[ \t]*[A-Za-z0-9_]+" _inh "${result}") if(NOT _inh) break() endif() set(_added FALSE) foreach(_entry IN LISTS _inh) string(REGEX REPLACE "^inherits:[ \t]*" "" _name "${_entry}") set(_file "${query_dir}/${_name}/highlights.scm") if(NOT EXISTS "${_file}" OR _file IN_LIST _visited) continue() endif() list(APPEND _visited "${_file}") file(READ "${_file}" _inh_text) string(APPEND result "\n${_inh_text}") set(_added TRUE) endforeach() if(NOT _added) break() endif() math(EXPR _depth "${_depth} + 1") endwhile() set(${outVar} "${result}" PARENT_SCOPE) endfunction() function(_ts_add_query sid text filesVar hashesVar) set(files "${${filesVar}}") set(hashes "${${hashesVar}}") string(SHA256 _ts_qh "${text}") if(_ts_qh IN_LIST hashes) return() endif() list(APPEND hashes "${_ts_qh}") list(LENGTH files _ts_qi) set(_ts_qfile "${CMAKE_CURRENT_BINARY_DIR}/ts-queries/${sid}_${_ts_qi}.scm") file(WRITE "${_ts_qfile}" "${text}") list(APPEND files "${_ts_qfile}") set(${filesVar} "${files}" PARENT_SCOPE) set(${hashesVar} "${hashes}" PARENT_SCOPE) endfunction() set(_ts_candidates "") file(GLOB _ts_sys_files "/usr/lib/libtree-sitter-*.so" "/usr/local/lib/libtree-sitter-*.so") foreach(_ts_file IN LISTS _ts_sys_files) get_filename_component(_ts_name "${_ts_file}" NAME) string(REGEX REPLACE "^libtree-sitter-(.+)\.so$" "\\1" _ts_id "${_ts_name}") string(REPLACE "-" "_" _ts_sid "${_ts_id}") _ts_entry_point(_ts_sym "${_ts_file}") list(APPEND _ts_candidates "${_ts_id}|${_ts_sid}|libtree-sitter-${_ts_id}.so|${_ts_sym}") endforeach() set(_ts_nvim_parser_dirs "$ENV{HOME}/.local/share/nvim/site/parser" "$ENV{HOME}/.local/share/nvim/runtime/parser" "$ENV{HOME}/.local/share/nvim/lazy/nvim-treesitter/parser") set(_ts_nvim_query_dirs "$ENV{HOME}/.local/share/nvim/site/queries" "$ENV{HOME}/.local/share/nvim/lazy/nvim-treesitter/runtime/queries") foreach(_ts_dir IN LISTS _ts_nvim_parser_dirs) file(GLOB _ts_dir_files "${_ts_dir}/*.so") foreach(_ts_file IN LISTS _ts_dir_files) get_filename_component(_ts_name "${_ts_file}" NAME) string(REGEX REPLACE "\\.so$" "" _ts_id "${_ts_name}") string(REPLACE "-" "_" _ts_sid "${_ts_id}") _ts_entry_point(_ts_sym "${_ts_file}") list(APPEND _ts_candidates "${_ts_id}|${_ts_sid}|${_ts_file}|${_ts_sym}") endforeach() endforeach() set(_ts_ids "") foreach(_ts_c IN LISTS _ts_candidates) string(REPLACE "|" ";" _ts_parts "${_ts_c}") list(GET _ts_parts 0 _ts_id) if(NOT _ts_id IN_LIST _ts_ids) list(APPEND _ts_ids "${_ts_id}") endif() endforeach() list(SORT _ts_ids) set(HIGHLIGHT_QUERIES_HPP "${CMAKE_CURRENT_BINARY_DIR}/highlight-queries.hpp") set(_hl_header "#pragma once\n\n// Generated by CMake. Discoverd tree-sitter grammars and their\n// highlight queries: vendored highlight-queries/*.scm (MIT), Neovim\n// nvim-treesitter queries, and tree-sitter/highlighting (MIT).\nnamespace ZShell::llm::hq {\nstruct Candidate { const char* lib; const char* symbol; };\nstruct Grammar { const char* id; int nCandidates; const Candidate* candidates; int nQueries; const char* const* queries; };\n") set(_ts_grammar_rows "") set(_ts_vendored c cpp python javascript typescript tsx bash json rust go yaml toml sql) foreach(_ts_id IN LISTS _ts_ids) string(REPLACE "-" "_" _ts_sid "${_ts_id}") set(_ts_qfiles "") set(_ts_qhashes "") if(_ts_id STREQUAL "cpp") file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/c.scm" _ts_qa) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/cpp.scm" _ts_qb) _ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes) elseif(_ts_id STREQUAL "typescript" OR _ts_id STREQUAL "tsx") file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/javascript.scm" _ts_qa) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/typescript.scm" _ts_qb) _ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes) _ts_add_query(${_ts_sid} "${_ts_qb}" _ts_qfiles _ts_qhashes) elseif(_ts_id IN_LIST _ts_vendored) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/${_ts_id}.scm" _ts_q) _ts_add_query(${_ts_sid} "${_ts_q}" _ts_qfiles _ts_qhashes) endif() foreach(_ts_qd IN LISTS _ts_nvim_query_dirs) if(EXISTS "${_ts_qd}/${_ts_id}/highlights.scm") file(READ "${_ts_qd}/${_ts_id}/highlights.scm" _ts_q) _ts_expand_inherits("${_ts_qd}" "${_ts_q}" _ts_q) _ts_add_query(${_ts_sid} "${_ts_q}" _ts_qfiles _ts_qhashes) endif() endforeach() if(NOT _ts_qfiles) set(_ts_dl "${CMAKE_CURRENT_BINARY_DIR}/ts-query-downloads/${_ts_sid}.scm") if(NOT EXISTS "${_ts_dl}") file(DOWNLOAD "https://raw.githubusercontent.com/tree-sitter/highlighting/main/queries/${_ts_id}/highlight.scm" "${_ts_dl}" STATUS _ts_dl_status TIMEOUT 30) list(GET _ts_dl_status 0 _ts_dl_rc) if(NOT _ts_dl_rc EQUAL 0) file(REMOVE "${_ts_dl}") endif() endif() if(EXISTS "${_ts_dl}") file(READ "${_ts_dl}" _ts_q) _ts_add_query(${_ts_sid} "${_ts_q}" _ts_qfiles _ts_qhashes) endif() endif() list(LENGTH _ts_qfiles _ts_nq) if(_ts_nq EQUAL 0) continue() endif() set(_ts_qn 0) set(_ts_q_ptrs "") foreach(_ts_qfile IN LISTS _ts_qfiles) file(READ "${_ts_qfile}" _ts_q) string(APPEND _hl_header "inline constexpr const char* q_${_ts_sid}_${_ts_qn} = R\"ZSQUERY(${_ts_q})ZSQUERY\";\n") string(APPEND _ts_q_ptrs "q_${_ts_sid}_${_ts_qn}, ") math(EXPR _ts_qn "${_ts_qn} + 1") endforeach() string(APPEND _hl_header "inline constexpr const char* const q_${_ts_sid}[] = { ${_ts_q_ptrs} };\n") string(APPEND _hl_header "inline constexpr Candidate cand_${_ts_sid}[] = {\n") set(_ts_nc 0) foreach(_ts_c IN LISTS _ts_candidates) string(REPLACE "|" ";" _ts_parts "${_ts_c}") list(GET _ts_parts 0 _ts_cid) if(_ts_cid STREQUAL _ts_id) list(GET _ts_parts 2 _ts_lib) list(GET _ts_parts 3 _ts_sym) string(APPEND _hl_header " { R\"ZSLIB(${_ts_lib})ZSLIB\", R\"ZSSYM(${_ts_sym})ZSSYM\" },\n") math(EXPR _ts_nc "${_ts_nc} + 1") endif() endforeach() string(APPEND _hl_header "};\n") if(_ts_nc EQUAL 0) string(APPEND _hl_header "") continue() endif() list(APPEND _ts_grammar_rows "{ \"${_ts_id}\", ${_ts_nc}, cand_${_ts_sid}, ${_ts_nq}, q_${_ts_sid} },") endforeach() string(APPEND _hl_header "inline constexpr Grammar grammars[] = {\n") foreach(_ts_row IN LISTS _ts_grammar_rows) string(APPEND _hl_header " ${_ts_row}\n") endforeach() string(APPEND _hl_header "};\n}\n") file(WRITE "${HIGHLIGHT_QUERIES_HPP}" "${_hl_header}") set(LM_FONTS lmroman10-regular lmroman10-italic lmroman10-bold lmroman10-bolditalic latinmodern-math) set(LM_FONTS_HPP "${CMAKE_CURRENT_BINARY_DIR}/latinmodern-fonts.hpp") set(_lm_header "#pragma once\n\n// Vendored Latin Modern fonts (GUST Font License; see\n// fonts/latinmodern/GUST-FONT-LICENSE.txt).\nnamespace ZShell::llm::lmfont {\n") foreach(_lm_font IN LISTS LM_FONTS) string(REPLACE "-" "_" _lm_sym "${_lm_font}") file(READ "${CMAKE_CURRENT_SOURCE_DIR}/fonts/latinmodern/${_lm_font}.otf" _lm_hex HEX) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," _lm_bytes "${_lm_hex}") string(APPEND _lm_header "inline const unsigned char ${_lm_sym}[] = { ${_lm_bytes} };\n") endforeach() string(APPEND _lm_header "}\n") file(WRITE "${LM_FONTS_HPP}" "${_lm_header}") qml_module(ZShell-llm URI ZShell.Llm SOURCES attachment.hpp attachment.cpp chat.hpp chat.cpp chatstore.hpp chatstore.cpp codehighlighter.hpp codehighlighter.cpp filetool.hpp filetool.cpp generation.hpp generation.cpp llmclient.hpp llmclient.cpp markdownblock.hpp markdownparser.hpp markdownparser.cpp mathtext.hpp mathtext.cpp message.hpp message.cpp messagemodel.hpp messagemodel.cpp segment.hpp segment.cpp session.hpp session.cpp shelltool.hpp shelltool.cpp tool.hpp tool.cpp webfetchtool.hpp webfetchtool.cpp LIBRARIES Qt::Network Qt::Sql Qt::Gui Qt::Widgets ZShell-config JKQTPlotter::JKQTMathText PkgConfig::CMARK_GFM PkgConfig::TREE_SITTER ) target_include_directories(ZShell-llm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})