Assembled from klammertext-dev f344a37d772c. The commands, the library,
the Standard Klammer Set, the reflection klammerset and the Python
binding build and run natively on Windows (MSYS2 UCRT64 gcc, python.org
Python), and both test tiers pass there. doc/install/windows_source_install.md
is the fifth install guide: a source install parallel to the Linux and
macOS ones, verified by following it on a pristine Windows 11.
Behaviour on every system: paths Klammertext prints use forward slashes;
output is LF; the command line is UTF-8 on Windows; @eval :shell is a
POSIX shell command everywhere -- on Windows it runs the sh Klammertext
ships, BusyBox for Windows (win/busybox/, GPLv2, with its licence and the
source pointer). KLAMMERTEXT_FONTS and KLAMMERTEXT_KLAMMERSETS are lists in
the system's PATH convention (';' on Windows). On Linux and macOS nothing
observable changes.
160 lines
4.8 KiB
C++
160 lines
4.8 KiB
C++
#include <iostream>
|
|
|
|
#include "character.h"
|
|
#include "locator.h"
|
|
#include "show.h"
|
|
#include "file.h"
|
|
#include "util.h"
|
|
|
|
std::string abbreviate_location(
|
|
const std::string& location, bool make_map,
|
|
std::map<std::string, std::string>& relpath)
|
|
{
|
|
std::string result = location;
|
|
fs::path basename = fs::path(location).filename();
|
|
if (sks_commands.contains(basename.string())) {
|
|
result = basename.string();
|
|
} else {
|
|
if (make_map) {
|
|
if (relpath.count(location)) {
|
|
result = relpath[location];
|
|
} else {
|
|
result = fs::relative(location, fs::current_path()).generic_string();
|
|
relpath[location] = result;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
Locator::Locator(const fs::path& filename, int line, int chr)
|
|
: m_filename(filename.generic_string())
|
|
, m_line(line)
|
|
, m_chr(chr)
|
|
{
|
|
string_map relpath {};
|
|
//m_filename = abbreviate_location(m_filename, false, relpath);
|
|
}
|
|
|
|
|
|
std::ostream &nformat(std::ostream &os)
|
|
{
|
|
os << std::setfill('0') << std::setw(3);
|
|
return os;
|
|
}
|
|
|
|
std::string Locator::str(bool relative) const
|
|
{
|
|
// relative_pathname(m_filename, fs::current_path().string()) << ":"
|
|
std::string filename = m_filename;
|
|
if (relative) {
|
|
filename = relative_to_cwd(m_filename).generic_string();
|
|
}
|
|
std::stringstream ss {};
|
|
ss << "[" << filename << ":"
|
|
<< nformat << m_line << "."
|
|
<< nformat << m_chr+1 << "]";
|
|
return ss.str();
|
|
}
|
|
|
|
std::string Locator::desc(bool relative) const
|
|
{
|
|
// relative_pathname(m_filename, fs::current_path().string()) << ":"
|
|
std::string filename = m_filename;
|
|
if (relative) {
|
|
filename = relative_to_cwd(m_filename).generic_string();
|
|
}
|
|
std::stringstream ss {};
|
|
ss << filename << ", line " << m_line << ", character " << m_chr + 1;
|
|
return ss.str();
|
|
}
|
|
|
|
std::string Locator::abbrev(bool include_chr) const
|
|
{
|
|
fs::path fname(m_filename);
|
|
std::stringstream ss {};
|
|
ss << "[" << fname.filename().string() << ":"
|
|
<< nformat << m_line;
|
|
if (include_chr) {
|
|
ss << "." << nformat << m_chr+1;
|
|
}
|
|
ss << "]";
|
|
return ss.str();
|
|
}
|
|
|
|
|
|
|
|
std::string locator_range(const Locator& start_loc, const Locator& end_loc, string_map& relpath)
|
|
{
|
|
std::string start_filename = abbreviate_location(start_loc.m_filename, true, relpath);
|
|
std::string end_filename = abbreviate_location(end_loc.m_filename, true, relpath);
|
|
|
|
std::stringstream ss {};
|
|
std::cout << std::setfill('0') << std::setw(3);
|
|
if (start_filename != end_filename) {
|
|
ss << start_loc << right_arrow << end_loc;
|
|
} else {
|
|
ss << "[" << start_filename << ":";
|
|
if (start_loc.m_line == end_loc.m_line) {
|
|
ss << nformat << start_loc.m_line << "."
|
|
<< nformat << start_loc.m_chr+1 << right_arrow
|
|
<< nformat << end_loc.m_chr+1;
|
|
} else {
|
|
ss << nformat << start_loc.m_line << "."
|
|
<< nformat << start_loc.m_chr+1
|
|
<< right_arrow
|
|
<< nformat << end_loc.m_line << "."
|
|
<< nformat << end_loc.m_chr+1;
|
|
}
|
|
ss << "]";
|
|
}
|
|
std::cout << std::setfill(' ');
|
|
return ss.str();
|
|
}
|
|
|
|
|
|
Locator current_locator(const std::source_location location)
|
|
{
|
|
// file_name() may be null (Homebrew GCC on macOS) -> avoid path(nullptr).
|
|
return Locator(location.file_name() ? location.file_name() : "",
|
|
location.line(), location.column());
|
|
}
|
|
|
|
std::string locator_summary(std::vector<Locator> locators)
|
|
{
|
|
std::map<std::string, std::vector<int>> file_locs {};
|
|
for (auto loc : locators) {
|
|
if (!file_locs.contains(loc.m_filename)) {
|
|
file_locs[loc.m_filename] = {};
|
|
}
|
|
file_locs[loc.m_filename].push_back(loc.m_line);
|
|
}
|
|
for (auto [filename, lines] : file_locs) {
|
|
std::cout << " " << filename << ": " << lines << "\n";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
// Parse "[<file>:<line>.<column>]" -- see the declaration in locator.h.
|
|
// Scanned from the RIGHT, because a pathname may itself contain ":" and
|
|
// "." while the line and column never do.
|
|
Locator Locator::from_string(const std::string& s)
|
|
{
|
|
if (s.size() < 6 || s.front() != '[' || s.back() != ']')
|
|
return Locator::none();
|
|
std::string body = s.substr(1, s.size() - 2);
|
|
size_t dot = body.rfind('.');
|
|
if (dot == std::string::npos) return Locator::none();
|
|
size_t colon = body.rfind(':', dot);
|
|
if (colon == std::string::npos) return Locator::none();
|
|
try {
|
|
int line = std::stoi(body.substr(colon + 1, dot - colon - 1));
|
|
int chr = std::stoi(body.substr(dot + 1));
|
|
// str() prints m_chr + 1; undo that so a round trip is exact.
|
|
return Locator(fs::path(body.substr(0, colon)), line, chr - 1);
|
|
} catch (const std::exception&) {
|
|
return Locator::none();
|
|
}
|
|
}
|