mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-06-26 10:54:28 +02:00
354 lines
9.6 KiB
C++
354 lines
9.6 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2006 - 2016, Paul Beckingham, Federico Hernandez.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
// http://www.opensource.org/licenses/mit-license.php
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <cmake.h>
|
|
#include <text.h>
|
|
#include <utf8.h>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <math.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void wrapText (
|
|
std::vector <std::string>& lines,
|
|
const std::string& text,
|
|
const int width,
|
|
bool hyphenate)
|
|
{
|
|
std::string line;
|
|
unsigned int offset = 0;
|
|
while (extractLine (line, text, width, hyphenate, offset))
|
|
lines.push_back (line);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::vector <std::string> split (const std::string& input, const char delimiter)
|
|
{
|
|
std::vector <std::string> results;
|
|
std::string::size_type start = 0;
|
|
std::string::size_type i;
|
|
while ((i = input.find (delimiter, start)) != std::string::npos)
|
|
{
|
|
results.push_back (input.substr (start, i - start));
|
|
start = i + 1;
|
|
}
|
|
|
|
if (input.length ())
|
|
results.push_back (input.substr (start));
|
|
|
|
return results;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
int longestWord (const std::string& input)
|
|
{
|
|
int longest = 0;
|
|
int length = 0;
|
|
std::string::size_type i = 0;
|
|
int character;
|
|
|
|
while ((character = utf8_next_char (input, i)))
|
|
{
|
|
if (character == ' ')
|
|
{
|
|
if (length > longest)
|
|
longest = length;
|
|
|
|
length = 0;
|
|
}
|
|
else
|
|
length += mk_wcwidth (character);
|
|
}
|
|
|
|
if (length > longest)
|
|
longest = length;
|
|
|
|
return longest;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
int longestLine (const std::string& input)
|
|
{
|
|
int longest = 0;
|
|
int length = 0;
|
|
std::string::size_type i = 0;
|
|
int character;
|
|
|
|
while ((character = utf8_next_char (input, i)))
|
|
{
|
|
if (character == '\n')
|
|
{
|
|
if (length > longest)
|
|
longest = length;
|
|
|
|
length = 0;
|
|
}
|
|
else
|
|
length += mk_wcwidth (character);
|
|
}
|
|
|
|
if (length > longest)
|
|
longest = length;
|
|
|
|
return longest;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Walk the input text looking for a break point. A break point is one of:
|
|
// - EOS
|
|
// - \n
|
|
// - last space before 'length' characters
|
|
// - last punctuation (, ; . :) before 'length' characters, even if not
|
|
// followed by a space
|
|
// - first 'length' characters
|
|
//
|
|
// text "one two three\n four"
|
|
// bytes 0123456789012 3456789
|
|
// characters 1234567890a23 4567890
|
|
//
|
|
// leading_ws
|
|
// ws ^ ^ ^^
|
|
// punct
|
|
// break ^
|
|
bool extractLine (
|
|
std::string& line,
|
|
const std::string& text,
|
|
int width,
|
|
bool hyphenate,
|
|
unsigned int& offset)
|
|
{
|
|
// Terminate processing.
|
|
// Note: bytes vs bytes.
|
|
if (offset >= text.length ())
|
|
return false;
|
|
|
|
std::string::size_type last_last_bytes = offset;
|
|
std::string::size_type last_bytes = offset;
|
|
std::string::size_type bytes = offset;
|
|
unsigned int last_ws = 0;
|
|
int character;
|
|
int char_width = 0;
|
|
int line_width = 0;
|
|
while (1)
|
|
{
|
|
last_last_bytes = last_bytes;
|
|
last_bytes = bytes;
|
|
character = utf8_next_char (text, bytes);
|
|
|
|
if (character == 0 ||
|
|
character == '\n')
|
|
{
|
|
line = text.substr (offset, last_bytes - offset);
|
|
offset = bytes;
|
|
break;
|
|
}
|
|
else if (character == ' ')
|
|
last_ws = last_bytes;
|
|
|
|
char_width = mk_wcwidth (character);
|
|
if (line_width + char_width > width)
|
|
{
|
|
int last_last_character = text[last_last_bytes];
|
|
int last_character = text[last_bytes];
|
|
|
|
// [case 1] one| two --> last_last != 32, last == 32, ws == 0
|
|
if (last_last_character != ' ' &&
|
|
last_character == ' ')
|
|
{
|
|
line = text.substr (offset, last_bytes - offset);
|
|
offset = last_bytes + 1;
|
|
break;
|
|
}
|
|
|
|
// [case 2] one |two --> last_last == 32, last != 32, ws != 0
|
|
else if (last_last_character == ' ' &&
|
|
last_character != ' ' &&
|
|
last_ws != 0)
|
|
{
|
|
line = text.substr (offset, last_bytes - offset - 1);
|
|
offset = last_bytes;
|
|
break;
|
|
}
|
|
|
|
else if (last_last_character != ' ' &&
|
|
last_character != ' ')
|
|
{
|
|
// [case 3] one t|wo --> last_last != 32, last != 32, ws != 0
|
|
if (last_ws != 0)
|
|
{
|
|
line = text.substr (offset, last_ws - offset);
|
|
offset = last_ws + 1;
|
|
break;
|
|
}
|
|
// [case 4] on|e two --> last_last != 32, last != 32, ws == 0
|
|
else
|
|
{
|
|
if (hyphenate)
|
|
{
|
|
line = text.substr (offset, last_bytes - offset - 1) + "-";
|
|
offset = last_last_bytes;
|
|
}
|
|
else
|
|
{
|
|
line = text.substr (offset, last_bytes - offset);
|
|
offset = last_bytes;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
line_width += char_width;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string format (std::string& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string format (const char* value)
|
|
{
|
|
std::string s (value);
|
|
return s;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string formatHex (int value)
|
|
{
|
|
std::stringstream s;
|
|
s.setf (std::ios::hex, std::ios::basefield);
|
|
s << value;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string format (float value, int width, int precision)
|
|
{
|
|
std::stringstream s;
|
|
s.width (width);
|
|
s.precision (precision);
|
|
if (0 < value && value < 1)
|
|
{
|
|
// For value close to zero, width - 2 (2 accounts for the first zero and
|
|
// the dot) is the number of digits after zero that are significant
|
|
double factor = 1;
|
|
for (int i = 2; i < width; i++)
|
|
factor *= 10;
|
|
value = roundf (value * factor) / factor;
|
|
}
|
|
s << value;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string format (double value, int width, int precision)
|
|
{
|
|
std::stringstream s;
|
|
s.width (width);
|
|
s.precision (precision);
|
|
if (0 < value && value < 1)
|
|
{
|
|
// For value close to zero, width - 2 (2 accounts for the first zero and
|
|
// the dot) is the number of digits after zero that are significant
|
|
double factor = 1;
|
|
for (int i = 2; i < width; i++)
|
|
factor *= 10;
|
|
value = round (value * factor) / factor;
|
|
}
|
|
s << value;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string format (double value)
|
|
{
|
|
std::stringstream s;
|
|
s << std::fixed << value;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void replace_positional (
|
|
std::string& fmt,
|
|
const std::string& from,
|
|
const std::string& to)
|
|
{
|
|
std::string::size_type pos = 0;
|
|
while ((pos = fmt.find (from, pos)) != std::string::npos)
|
|
{
|
|
fmt.replace (pos, from.length (), to);
|
|
pos += to.length ();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::string leftJustify (const int input, const int width)
|
|
{
|
|
std::stringstream s;
|
|
s << input;
|
|
std::string output = s.str ();
|
|
return output + std::string (width - output.length (), ' ');
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::string leftJustify (const std::string& input, const int width)
|
|
{
|
|
return input + std::string (width - utf8_text_width (input), ' ');
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::string rightJustifyZero (const int input, const int width)
|
|
{
|
|
std::stringstream s;
|
|
s << std::setw (width) << std::setfill ('0') << input;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::string rightJustify (const int input, const int width)
|
|
{
|
|
std::stringstream s;
|
|
s << std::setw (width) << std::setfill (' ') << input;
|
|
return s.str ();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
std::string rightJustify (const std::string& input, const int width)
|
|
{
|
|
unsigned int len = utf8_text_width (input);
|
|
return (((unsigned int) width > len)
|
|
? std::string (width - len, ' ')
|
|
: "")
|
|
+ input;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|