From 4fe8d16a2042dc2916499730f634db7906e2e434 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sat, 31 Jan 2026 18:03:11 +0100 Subject: [PATCH] Add support for source file links in markdown renderer. --- profiler/src/main.cpp | 2 +- profiler/src/profiler/TracyLlm.cpp | 4 +-- profiler/src/profiler/TracyLlm.hpp | 3 +- profiler/src/profiler/TracyLlmChat.cpp | 3 +- profiler/src/profiler/TracyLlmChat.hpp | 5 ++- profiler/src/profiler/TracyMarkdown.cpp | 47 +++++++++++++++++++++++-- profiler/src/profiler/TracyMarkdown.hpp | 7 +++- profiler/src/profiler/TracyView.cpp | 6 ++-- 8 files changed, 65 insertions(+), 12 deletions(-) diff --git a/profiler/src/main.cpp b/profiler/src/main.cpp index 2232079b..92a040dd 100644 --- a/profiler/src/main.cpp +++ b/profiler/src/main.cpp @@ -1345,7 +1345,7 @@ The *Achievements* system will guide you through the main features and teach you Would you like to enable achievements? )"; - tracy::Markdown md; + tracy::Markdown md( nullptr, nullptr ); md.Print( text, strlen( text ) ); ImGui::Spacing(); ImGui::PushFont( g_fonts.normal, FontSmall ); diff --git a/profiler/src/profiler/TracyLlm.cpp b/profiler/src/profiler/TracyLlm.cpp index 48e9bf0b..ccbf8a99 100644 --- a/profiler/src/profiler/TracyLlm.cpp +++ b/profiler/src/profiler/TracyLlm.cpp @@ -25,7 +25,7 @@ extern double s_time; constexpr size_t InputBufferSize = 1024; -TracyLlm::TracyLlm( Worker& worker, const TracyManualData& manual ) +TracyLlm::TracyLlm( Worker& worker, View& view, const TracyManualData& manual ) : m_exit( false ) , m_input( nullptr ) { @@ -48,7 +48,7 @@ TracyLlm::TracyLlm( Worker& worker, const TracyManualData& manual ) ResetChat(); m_api = std::make_unique(); - m_chatUi = std::make_unique(); + m_chatUi = std::make_unique( view, worker ); m_tools = std::make_unique( worker, manual ); m_busy = true; diff --git a/profiler/src/profiler/TracyLlm.hpp b/profiler/src/profiler/TracyLlm.hpp index a514a804..6176b93b 100644 --- a/profiler/src/profiler/TracyLlm.hpp +++ b/profiler/src/profiler/TracyLlm.hpp @@ -20,6 +20,7 @@ class TracyLlmApi; class TracyLlmChat; class TracyLlmTools; class TracyManualData; +class View; class Worker; class TracyLlm @@ -43,7 +44,7 @@ class TracyLlm }; public: - TracyLlm( Worker& worker, const TracyManualData& manual ); + TracyLlm( Worker& worker, View& view, const TracyManualData& manual ); ~TracyLlm(); [[nodiscard]] bool IsBusy() const { std::lock_guard lock( m_lock ); return m_busy; } diff --git a/profiler/src/profiler/TracyLlmChat.cpp b/profiler/src/profiler/TracyLlmChat.cpp index f46782a7..9c09de29 100644 --- a/profiler/src/profiler/TracyLlmChat.cpp +++ b/profiler/src/profiler/TracyLlmChat.cpp @@ -67,8 +67,9 @@ static const char* utfendl( const char* str, int len ) } -TracyLlmChat::TracyLlmChat() +TracyLlmChat::TracyLlmChat( View& view, Worker& worker ) : m_width( new float[NumRoles] ) + , m_markdown( &view, &worker ) { } diff --git a/profiler/src/profiler/TracyLlmChat.hpp b/profiler/src/profiler/TracyLlmChat.hpp index 6dfd0a84..e95defca 100644 --- a/profiler/src/profiler/TracyLlmChat.hpp +++ b/profiler/src/profiler/TracyLlmChat.hpp @@ -8,6 +8,9 @@ namespace tracy { +class View; +class Worker; + class TracyLlmChat { public: @@ -32,7 +35,7 @@ public: ToolCall }; - TracyLlmChat(); + TracyLlmChat( View& view, Worker& worker ); ~TracyLlmChat(); void Begin(); diff --git a/profiler/src/profiler/TracyMarkdown.cpp b/profiler/src/profiler/TracyMarkdown.cpp index 8fefd344..1a459132 100644 --- a/profiler/src/profiler/TracyMarkdown.cpp +++ b/profiler/src/profiler/TracyMarkdown.cpp @@ -8,6 +8,7 @@ #include "TracyMouse.hpp" #include "TracyImGui.hpp" #include "TracySourceContents.hpp" +#include "TracyView.hpp" #include "TracyWeb.hpp" #include "../Fonts.hpp" @@ -39,6 +40,8 @@ class MarkdownContext }; public: + MarkdownContext( View* view, Worker* worker ) : m_view( view ), m_worker( worker ) {} + int EnterBlock( MD_BLOCKTYPE type, void* detail ) { switch( type ) @@ -285,7 +288,40 @@ public: ImGui::TextUnformatted( link.c_str() ); ImGui::PopStyleColor(); ImGui::EndTooltip(); - if( IsMouseClicked( ImGuiMouseButton_Left ) ) OpenWebpage( link.c_str() ); + if( IsMouseClicked( ImGuiMouseButton_Left ) ) + { + if( link.starts_with( "source:" ) ) + { + if( m_view && m_worker ) + { + std::string source = link.substr( 7 ); + auto separator = source.find_last_of( ':' ); + int line; + std::string fn; + if( separator != std::string::npos ) + { + fn = source.substr( 0, separator ); + line = atoi( source.substr( separator + 1 ).c_str() ); + } + else + { + fn = source; + line = 0; + } + + const auto idx = m_worker->FindStringIdx( fn.c_str() ); + if( idx != 0 ) + { + auto str = m_worker->GetString( StringIdx( idx ) ); + m_view->ViewSource( str, line ); + } + } + } + else + { + OpenWebpage( link.c_str() ); + } + } } } break; @@ -379,11 +415,16 @@ private: std::vector lists; std::string link; + + View* m_view; + Worker* m_worker; }; -Markdown::Markdown() +Markdown::Markdown( View* view, Worker* worker ) : m_parser( new MD_PARSER() ) + , m_view( view ) + , m_worker( worker ) { memset( m_parser, 0, sizeof( MD_PARSER ) ); m_parser->flags = MD_FLAG_COLLAPSEWHITESPACE | MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_NOHTML | MD_FLAG_TABLES | MD_FLAG_TASKLISTS | MD_FLAG_STRIKETHROUGH; @@ -403,7 +444,7 @@ void Markdown::Print( const char* str, size_t size ) { ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( ImGui::GetStyle().ItemSpacing.x, 0.0f ) ); - MarkdownContext md; + MarkdownContext md( m_view, m_worker ); md_parse( str, size, m_parser, &md ); ImGui::PopStyleVar(); diff --git a/profiler/src/profiler/TracyMarkdown.hpp b/profiler/src/profiler/TracyMarkdown.hpp index 18346a96..b8897af2 100644 --- a/profiler/src/profiler/TracyMarkdown.hpp +++ b/profiler/src/profiler/TracyMarkdown.hpp @@ -8,16 +8,21 @@ struct MD_PARSER; namespace tracy { +class View; +class Worker; + class Markdown { public: - Markdown(); + Markdown( View* view, Worker* worker ); ~Markdown(); void Print( const char* str, size_t size ); private: MD_PARSER* m_parser; + View* m_view; + Worker* m_worker; }; } diff --git a/profiler/src/profiler/TracyView.cpp b/profiler/src/profiler/TracyView.cpp index a111a5ed..cf18e7ee 100644 --- a/profiler/src/profiler/TracyView.cpp +++ b/profiler/src/profiler/TracyView.cpp @@ -59,11 +59,12 @@ View::View( void(*cbMainThread)(const std::function&, bool), const char* , m_horizontalScrollMultiplier( s_config.horizontalScrollMultiplier ) , m_verticalScrollMultiplier( s_config.verticalScrollMultiplier ) , m_manualData( std::make_shared() ) + , m_markdown( nullptr, nullptr ) #ifdef __EMSCRIPTEN__ , m_td( 2, "ViewMt" ) #else , m_td( std::thread::hardware_concurrency(), "ViewMt" ) - , m_llm( m_worker, *m_manualData ) + , m_llm( m_worker, *this, *m_manualData ) #endif { InitTextEditor(); @@ -89,11 +90,12 @@ View::View( void(*cbMainThread)(const std::function&, bool), FileRead& f , m_horizontalScrollMultiplier( s_config.horizontalScrollMultiplier ) , m_verticalScrollMultiplier( s_config.verticalScrollMultiplier ) , m_manualData( std::make_shared() ) + , m_markdown( nullptr, nullptr ) #ifdef __EMSCRIPTEN__ , m_td( 2, "ViewMt" ) #else , m_td( std::thread::hardware_concurrency(), "ViewMt" ) - , m_llm( m_worker, *m_manualData ) + , m_llm( m_worker, *this, *m_manualData ) #endif { m_notificationTime = 4;