imgui_md
imgui_md copied to clipboard
Added support for numeric character references and task lists
Hello
Thanks for sharing your wonderful library. I have added a couple of features buy I won't make a pull request because the custom renderer I'm using make it incompatible with the standard font handling and also I realized too late that I have my text editor configured to change tabs to spaces.
However I'll post here the relevant code fragments in case you find them useful.
Here's how it looks:
And now the code.
For numeric character references:
#include <charconv>
// Adapted from RapidJSON (MIT licence)
static std::string UTF8Encoder(unsigned int aCodePoint)
{
std::string res="";
if (aCodePoint <= 0x79)
{
res.push_back(static_cast<char>(aCodePoint & 0xFF));
}
else if (aCodePoint <= 0x7FF)
{
res.push_back(static_cast<char>(0xC0 | ((aCodePoint >> 6) & 0xFF)));
res.push_back(static_cast<char>(0x80 | ((aCodePoint & 0x3F))));
}
else if (aCodePoint <= 0xFFFF)
{
res.push_back(static_cast<char>(0xE0 | ((aCodePoint >> 12) & 0xFF)));
res.push_back(static_cast<char>(0x80 | ((aCodePoint >> 6) & 0x3F)));
res.push_back(static_cast<char>(0x80 | (aCodePoint & 0x3F)));
}
else
{
//ASSERT(codepoint <= 0x10FFFF);
res.push_back(static_cast<char>(0xF0 | ((aCodePoint >> 18) & 0xFF)));
res.push_back(static_cast<char>(0x80 | ((aCodePoint >> 12) & 0x3F)));
res.push_back(static_cast<char>(0x80 | ((aCodePoint >> 6) & 0x3F)));
res.push_back(static_cast<char>(0x80 | (aCodePoint & 0x3F)));
}
return res;
}
bool imgui_md::render_entity(const char* str, const char* str_end)
{
const size_t sz = str_end - str;
if (strncmp(str, " ", sz) == 0) {
ImGui::TextUnformatted(""); ImGui::SameLine();
return true;
}
if(sz<4)
{
return false;
}
if (strncmp(str, "&#", 2) == 0 )
{
int base,offset;
if(*(str+2)=='x' || *(str+2)=='X')
{
base=16;
offset=3;
}
else
{
base=10;
offset=2;
}
int code_point;
auto [ptr, ec] = std::from_chars(str+offset, str_end, code_point,base);
if (ec == std::errc())
{
if(code_point>= 0xD800 && code_point<=0xDBFF)
{
// TODO: Handle UTF-16 surrogate pair
return false;
}
std::string utf8_char=UTF8Encoder(code_point);
ImGui::TextUnformatted(utf8_char.c_str(),utf8_char.c_str()+utf8_char.size()); ImGui::SameLine(0.0f,0.0f);
return true;
}
}
return false;
}
For task list:
I have added a member variable to personalize indent.
float m_indent_size=40.0f;
And now the BLOCK_LI function becomes:
void imgui_md::BLOCK_LI(const MD_BLOCK_LI_DETAIL* aDetailBlockLI, bool e)
{
if (e) {
ImGui::NewLine();
list_info& nfo = m_list_stack.back();
if (nfo.is_ol) {
ImGui::Text("%d%c", nfo.cur_ol++, nfo.delim);
ImGui::SameLine();
} else {
if (nfo.delim == '*') {
float cx = ImGui::GetCursorPosX();
cx -= ImGui::GetStyle().FramePadding.x * 2;
ImGui::SetCursorPosX(cx);
ImGui::Bullet();
} else {
ImGui::Text("%c", nfo.delim);
ImGui::SameLine();
}
}
ImGui::Indent(m_indent_size);
if(aDetailBlockLI->is_task)
{
bool v=(aDetailBlockLI->task_mark=='x' || aDetailBlockLI->task_mark=='X');
ImGui::Checkbox("##task",&v);
ImGui::SameLine(0.0f,m_indent_size*0.25f);
}
} else {
ImGui::Unindent(m_indent_size);
}
}
Hope you find it useful.