Skip to content

Commit

Permalink
add support for unwrapping quoted lines before wrapping them on reply
Browse files Browse the repository at this point in the history
  • Loading branch information
d99kris committed Aug 3, 2024
1 parent d80accd commit 25be36d
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 3 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ file (platform-dependent defaults are left empty below):
terminal_title=
top_bar_show_version=0
unread_indicator=N
unwrap_quoted_lines=1

### attachment_indicator

Expand Down Expand Up @@ -1027,6 +1028,11 @@ Specifies custom terminal title, ex: `terminal_title=nmail - [email protected]`.
Controls which character to indicate that an email is unread (default: `N`).
For a more graphical interface, an emoji such as `` can be used.

### unwrap_quoted_lines

Specifies whether nmail shall unwrap quoted lines before wrapping them when
composing a message reply.


~/.config/nmail/colors.conf
---------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/nmail.1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
.TH NMAIL "1" "August 2024" "nmail 5.1.8" "User Commands"
.TH NMAIL "1" "August 2024" "nmail 5.1.9" "User Commands"
.SH NAME
nmail \- ncurses mail
.SH SYNOPSIS
Expand Down
11 changes: 10 additions & 1 deletion src/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ void Ui::Init()
{ "signature", "0" },
{ "terminal_title", "" },
{ "top_bar_show_version", "0" },
{ "unwrap_quoted_lines", "1" },
};
const std::string configPath(Util::GetApplicationDir() + std::string("ui.conf"));
m_Config = Config(configPath, defaultConfig);
Expand Down Expand Up @@ -358,6 +359,7 @@ void Ui::Init()
Util::SetLocalizedSubjectPrefixes(m_Config.Get("localized_subject_prefixes"));
m_Signature = m_Config.Get("signature") == "1";
m_TopBarShowVersion = m_Config.Get("top_bar_show_version") == "1";
m_UnwrapQuotedLines = m_Config.Get("unwrap_quoted_lines") == "1";

try
{
Expand Down Expand Up @@ -3541,6 +3543,13 @@ void Ui::SetState(Ui::State p_State)
}

std::string indentBodyText = Util::AddIndent(bodyText, "> ");
const int quotedMaxLen = 78;

if (m_UnwrapQuotedLines)
{
indentBodyText = Util::UnwrapQuotedLines(indentBodyText, quotedMaxLen);
}

std::string indentBody;
if (m_ComposeLineWrap == LineWrapFormatFlowed)
{
Expand All @@ -3553,7 +3562,7 @@ void Ui::SetState(Ui::State p_State)
const bool quoteWrap = m_RewrapQuotedLines;
const int expandTabSize = m_TabSize; // enabled
std::vector<std::wstring> indentBodyLines =
Util::WordWrap(Util::ToWString(indentBodyText), 72, processFlowed, outputFlowed, quoteWrap, expandTabSize);
Util::WordWrap(Util::ToWString(indentBodyText), quotedMaxLen, processFlowed, outputFlowed, quoteWrap, expandTabSize);
indentBody = Util::ToString(Util::Join(indentBodyLines));
}

Expand Down
1 change: 1 addition & 0 deletions src/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ class Ui
bool m_SearchShowFolder = false;
bool m_Signature = false;
bool m_TopBarShowVersion = false;
bool m_UnwrapQuotedLines = false;

std::string m_TerminalTitle;

Expand Down
79 changes: 79 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1958,6 +1958,24 @@ std::string Util::ZeroPad(uint32_t p_Num, int32_t p_Len)
return str;
}

bool Util::GetQuotePrefix(const std::string& p_String, std::string& p_Prefix, std::string& p_Line)
{
std::smatch sm;
std::regex re("^(( *> *)+)");
if (std::regex_search(p_String, sm, re))
{
p_Prefix = sm.str();
p_Line = sm.suffix();
return true;
}
else
{
p_Prefix.clear();
p_Line = p_String;
return false;
}
}

bool Util::GetQuotePrefix(const std::wstring& p_String, std::wstring& p_Prefix, std::wstring& p_Line)
{
std::wsmatch sm;
Expand Down Expand Up @@ -2317,3 +2335,64 @@ std::string Util::GetDefaultApplicationDir()
static const std::string applicationDir = configHomeDir + "/nmail";
return applicationDir;
}

std::string Util::UnwrapQuotedLines(const std::string& p_Msg, int p_LineLen)
{
const std::vector<std::string> lines = Split(Strip(p_Msg, '\r'), '\n');
const int lineCnt = lines.size();
std::vector<std::string> outlines;
std::string outline;
std::string outprefix;
std::string curline;
std::string curprefix;
for (int i = 0; i < lineCnt; ++i)
{
GetQuotePrefix(lines[i], curprefix, curline);
const std::string curtrimline = Trim(curline);
const int curfirstwordlen = curtrimline.empty() ? 0 : Split(curtrimline, ' ').at(0).size();
const int prevlinesize = (i > 0) ? lines[i - 1].size() : 0;
if ((outprefix == curprefix) && !curtrimline.empty() && ((prevlinesize + curfirstwordlen + 1) >= p_LineLen))
{
// Same prefix and previous line plus current lines first word exceed wrap width -> unwrap and append to outline
if (!outline.empty())
{
outline += " ";
}

outline += curline;
}
else
{
if (!outline.empty())
{
// Terminate non-empty outline and start new
outlines.push_back(outprefix + outline);
outline = "";
}

if (curtrimline.empty())
{
// Append blank line for empty input line
outlines.push_back(curprefix + curtrimline);
outline = "";
}
else
{
// Set outline to current line
outline = curtrimline;
}

// Update outprefix
outprefix = curprefix;
}
}

if (!outline.empty())
{
// Append any remaining buffered outline
outlines.push_back(outprefix + outline);
}

// Return joined string
return Join(outlines, "\n");
}
2 changes: 2 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ class Util
static void NormalizeSubject(std::string& p_String, bool p_ToLower);
static void SetLocalizedSubjectPrefixes(const std::string& p_Prefixes);
static std::string ZeroPad(uint32_t p_Num, int32_t p_Len);
static bool GetQuotePrefix(const std::string& p_String, std::string& p_Prefix, std::string& p_Line);
static bool GetQuotePrefix(const std::wstring& p_String, std::wstring& p_Prefix, std::wstring& p_Line);
static std::string ToHex(const std::string& p_String);
static std::string FromHex(const std::string& p_String);
Expand Down Expand Up @@ -296,6 +297,7 @@ class Util
static std::string ExtractString(const std::string& p_Str, const std::string& p_Prefix, const std::string& p_Suffix);
static bool IsIpAddress(const std::string& p_Str);
static std::string GetDefaultApplicationDir();
static std::string UnwrapQuotedLines(const std::string& p_Msg, int p_LineLen);

template<typename T>
static inline void Unused(const T& p_Arg)
Expand Down
2 changes: 1 addition & 1 deletion src/version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include "version.h"

#define NMAIL_VERSION "5.1.8"
#define NMAIL_VERSION "5.1.9"

std::string Version::GetBuildOs()
{
Expand Down

0 comments on commit 25be36d

Please sign in to comment.