mudlet/src/TTrigger.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1550 lines
58 KiB
C++
Raw Permalink Normal View History

/***************************************************************************
* Copyright (C) 2008-2013 by Heiko Koehn - KoehnHeiko@googlemail.com *
* Copyright (C) 2014 by Ahmed Charles - acharles@outlook.com *
* Copyright (C) 2016 by Chris Leacy - cleacy1972@gmail.com *
* Copyright (C) 2017-2018, 2021, 2026 by Stephen Lyons *
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
* - slysven@virginmedia.com *
2009-01-24 02:50:22 +01:00
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
2009-01-24 02:50:22 +01:00
#include "TTrigger.h"
2009-01-24 02:50:22 +01:00
#include "Host.h"
#include "TConsole.h"
2009-01-24 02:50:22 +01:00
#include "TDebug.h"
#include "TMatchState.h"
#include "TMedia.h"
2017-04-14 00:40:02 -07:00
#include "mudlet.h"
#include <QRegularExpression>
#include <cassert>
#include <sstream>
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// Some extraordinary numbers outside of the range (0-255) used for ANSI colors:
// Changing them WILL modify the Lua API of TLuaInterpreter::tempColorTrigger
// and the replacement TLuaInterpreter::tempAnsiColorTrigger
const int TTrigger::scmDefault = -2;
const int TTrigger::scmIgnored = -1;
TTrigger::TTrigger(TTrigger* parent, Host* pHost)
: Tree<TTrigger>(parent)
, mpHost(pHost)
, mpLua(mpHost->getLuaInterpreter())
2009-01-24 02:50:22 +01:00
{
2010-03-18 16:07:12 +01:00
}
2009-01-24 02:50:22 +01:00
TTrigger::TTrigger(const QString& name, const QStringList& patterns, const QList<int>& patternKinds, bool isMultiline, Host* pHost)
: Tree<TTrigger>(nullptr)
, mpHost(pHost)
, mName(name)
, mPatterns(patterns)
, mPatternKinds(patternKinds)
, mIsMultiline(isMultiline)
, mpLua(mpHost->getLuaInterpreter())
2009-01-24 02:50:22 +01:00
{
setRegexCodeList(patterns, patternKinds);
2009-01-24 02:50:22 +01:00
}
TTrigger::~TTrigger()
{
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.clear();
mConditionMap.clear();
if (!mpHost) {
2010-01-22 01:45:34 +01:00
return;
2009-01-24 02:50:22 +01:00
}
mpHost->getTriggerUnit()->unregisterTrigger(this);
if (isTemporary()) {
if (mScript.isEmpty()) {
mpHost->mLuaInterpreter.delete_luafunction(this);
} else {
mpHost->mLuaInterpreter.delete_luafunction(mFuncName);
}
}
2009-01-24 02:50:22 +01:00
}
void TTrigger::setName(const QString& name)
{
if (!isTemporary()) {
Merge release-4.0 back into development (#2918) * Remove left over debug statement for command line (#2885) * Fix permGroup for aliases and timers (#2887) * Remove text unnecessary for proxy translation (#2892) * Update autocomplete list for 4.0 (#2896) * Fix no patterns being set for triggers (#2891) * Default-initialise the repeating boolean (#2899) * Revert trigger editor changes (#2898) * Revert "Fix no patterns being set for triggers (#2891)" This reverts commit 0913755c091fef5a89ebd1a883f2e685061c6cc5. * Revert "Fix errors when creating new triggers (#2868)" This reverts commit 0578c6142889baee5c65d22b958960b1539e31ec. * Add supporters tab (#2880) (#2906) * Add initial tab and icon * Refactor text setting into separate methods * Comment improvement * Added a super simplistic structure for the Patreon tab * Added new HTML in * Add images * Remove PlaceholderText, fix Qt 5.7 compile * Add images in * Add missing end tag * Remove obsolete end tag * Set minimum size on about dialog to one that looks okay * Re-save with GIMP and fix libpng warnings * Draw our own images * Update names and white space * Layout * Typo * Dont create if already existing * Dont crash when closing Mudlet * Drop %3, save screen space * Don't print supporter's introduction big (cherry picked from commit 278d49f520318362328a02b6a49003003fa4eddd) * Update Windows Qt - 4.0 edition (#2911) * Move appveyor and windows SDK to Qt 5.12.4 * Fix macOS crash when saving settings (#2915) * 4.0.0 release * Re-set dev * Use OpenSSL 1.1.1 on Windows (#2923) * Use OpenSSL 1.1.1 on Windows * Set release build * Reset -dev * Fix dblsqd auto attachment * Fix mudletOlderThan() for 4.0 (#2925) (#2928) * mudletOlderThan fix * Logic adjustments * Combine and straighten else clauses (cherry picked from commit 42295a8526e005c89fd089106778ca5374184ee8) * Fix Patreon link in Supporters tab to open browser (#2927) (#2930) (cherry picked from commit 5647fe9628317f5e59fab845f2e191e88bb62dcb) * New Crowdin translations (#2838) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Dutch) * New translations mudlet.ts (English, United Kingdom) * New translations mudlet.ts (French) * New translations mudlet.ts (German) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Polish) * New translations mudlet.ts (Portuguese) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Spanish) * New translations mudlet.ts (Chinese Traditional) * New translations mudlet.ts (Greek) * New translations mudlet.ts (Pirate English) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (English, United Kingdom) * New translations mudlet.ts (French) * New translations mudlet.ts (German) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Polish) * New translations mudlet.ts (Portuguese) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Spanish) * New translations mudlet.ts (Chinese Traditional) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (German) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (German) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (French) * New translations mudlet.ts (French) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Dutch) * New translations mudlet.ts (English, United Kingdom) * New translations mudlet.ts (French) * New translations mudlet.ts (German) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Polish) * New translations mudlet.ts (Portuguese) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Spanish) * New translations mudlet.ts (Chinese Traditional) * New translations mudlet.ts (Greek) * New translations mudlet.ts (Pirate English) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (French) * New translations mudlet.ts (German) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Polish) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Russian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Chinese Simplified) * New translations mudlet.ts (Italian) * New translations mudlet.ts (Italian) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (German) * New translations mudlet.ts (Chinese Simplified) (cherry picked from commit 96e25f556f7a5020a41f1131b5cd4cad58af82ed) * 4.0.2 hotfix release * Use Qt 5.12.3 for Windows Mudlet (#2932) * Properly initialise ssl and proxy settings (#2931) * Actual 4.0.2 hotfix release * Re-set dev * Revert "Use OpenSSL 1.1.1 on Windows (#2923)" (#2934) This reverts commit 4127624fee124bdac5324d7b2a5c11cc13a81ec1. * 4.0.3 hotfix release (re-enable TLS/SSL in Windows) * Re-set dev
2019-08-08 06:09:38 +02:00
mpHost->getTriggerUnit()->mLookupTable.remove(mName, this);
2009-11-14 02:46:52 +01:00
}
mName = name;
mpHost->getTriggerUnit()->mLookupTable.insert(name, this);
}
static void pcre2_code_deleter(pcre2_code* pointer)
{
pcre2_code_free(pointer);
}
fix: trigger matching no longer allocates memory for every pattern on every line (#9852) #### Brief overview of PR changes/additions - `match_perl()` called `pcre2_match_data_create_from_pattern()` + `pcre2_match_data_free()` on every call: one heap allocation and free per Perl-regex pattern, per reachable trigger, per line of game text. - Cache one `match_data` per compiled pattern and reuse it across lines, in a `QSharedPointer` with a deleter to match how `mRegexMap` already owns its `pcre2_code`. Cleared alongside `mRegexMap` when patterns are recompiled, since each block is sized from its pattern's capture count. - Reuse is safe under re-entrancy: `processRegexMatch()` copies every capture out of the ovector into `captureList` before calling `execute()`, so a script that calls `feedTriggers()` and re-enters `match_perl()` on the same pattern cannot clobber an ovector still being read. #### Motivation for adding to Mudlet This is a regression, not a missed optimisation: before #8533 migrated the regex engine to PCRE2 the match results went into a stack array (`int ovector[MAX_CAPTURE_GROUPS]`), and the per-call heap allocation arrived unnoticed with PCRE2's API style. #### Other info (issues closed, discussion etc) Measured with `PipelineBenchmark` on macOS/arm64, Release, `-DUSE_SANITIZER=""`, using two binaries from one toolchain run in 24 interleaved ABBA pairs (alternating order, so run-order effects cancel): trigger throughput **+3.11%** (t=3.00), trigger overhead **-5.51%** (t=-2.13). The text-only control moved -0.92% (t=-0.26, 12/24 paired wins) i.e. no effect, which is the check that the trigger deltas are real. ASan must be off for this measurement since it instruments every malloc. **Test case:** behaviour-neutral, so the checks are for regressions. Perl-regex triggers with 2 and 3 capture groups firing on one line both return correct captures; editing a saved trigger's pattern to one with a different capture count then re-firing still returns correct captures (exercises cache invalidation); a trigger whose script calls `feedTriggers()` into a second Perl trigger still fires correctly (exercises re-entrancy). Verified against before/after builds on macOS, plus 6 trigger functional test suites. --------- Signed-off-by: Jay Howard <jay.patrick.howard@gmail.com>
2026-08-13 08:46:35 -05:00
static void pcre2_match_data_deleter(pcre2_match_data* pointer)
{
pcre2_match_data_free(pointer);
}
//FIXME: lock if code *OR* regex doesn't compile
bool TTrigger::setRegexCodeList(QStringList patterns, QList<int> patternKinds, bool existingTrigger)
2009-01-24 02:50:22 +01:00
{
patterns.replaceInStrings("\n", "");
mPatterns.clear();
2009-01-24 02:50:22 +01:00
mRegexMap.clear();
fix: trigger matching no longer allocates memory for every pattern on every line (#9852) #### Brief overview of PR changes/additions - `match_perl()` called `pcre2_match_data_create_from_pattern()` + `pcre2_match_data_free()` on every call: one heap allocation and free per Perl-regex pattern, per reachable trigger, per line of game text. - Cache one `match_data` per compiled pattern and reuse it across lines, in a `QSharedPointer` with a deleter to match how `mRegexMap` already owns its `pcre2_code`. Cleared alongside `mRegexMap` when patterns are recompiled, since each block is sized from its pattern's capture count. - Reuse is safe under re-entrancy: `processRegexMatch()` copies every capture out of the ovector into `captureList` before calling `execute()`, so a script that calls `feedTriggers()` and re-enters `match_perl()` on the same pattern cannot clobber an ovector still being read. #### Motivation for adding to Mudlet This is a regression, not a missed optimisation: before #8533 migrated the regex engine to PCRE2 the match results went into a stack array (`int ovector[MAX_CAPTURE_GROUPS]`), and the per-call heap allocation arrived unnoticed with PCRE2's API style. #### Other info (issues closed, discussion etc) Measured with `PipelineBenchmark` on macOS/arm64, Release, `-DUSE_SANITIZER=""`, using two binaries from one toolchain run in 24 interleaved ABBA pairs (alternating order, so run-order effects cancel): trigger throughput **+3.11%** (t=3.00), trigger overhead **-5.51%** (t=-2.13). The text-only control moved -0.92% (t=-0.26, 12/24 paired wins) i.e. no effect, which is the check that the trigger deltas are real. ASan must be off for this measurement since it instruments every malloc. **Test case:** behaviour-neutral, so the checks are for regressions. Perl-regex triggers with 2 and 3 capture groups firing on one line both return correct captures; editing a saved trigger's pattern to one with a different capture count then re-firing still returns correct captures (exercises cache invalidation); a trigger whose script calls `feedTriggers()` into a second Perl trigger still fires correctly (exercises re-entrancy). Verified against before/after builds on macOS, plus 6 trigger functional test suites. --------- Signed-off-by: Jay Howard <jay.patrick.howard@gmail.com>
2026-08-13 08:46:35 -05:00
mMatchDataMap.clear();
mPatternKinds.clear();
mLuaConditionMap.clear();
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.clear();
2009-01-24 02:50:22 +01:00
mTriggerContainsPerlRegex = false;
if (patternKinds.size() != patterns.size()) {
//FIXME: ronny managed to trigger this somehow
qDebug() << "[CRITICAL ERROR (plz report):] Trigger name=" << mName << " aborting reason: patternKinds.size() != patterns.size()";
}
if (existingTrigger && (patternKinds.empty()) && (!isFolder()) && (!mColorTrigger)) {
setError(tr("error: this trigger has no patterns defined"));
mOK_init = false;
2009-04-09 21:42:11 +02:00
return false;
2009-01-24 02:50:22 +01:00
}
2009-04-09 21:42:11 +02:00
bool state = true;
if (existingTrigger) {
for (int i = 0; i < patterns.size(); i++) {
if (patterns.at(i).isEmpty() && patternKinds.at(i) != REGEX_PROMPT) {
continue;
}
2010-03-18 16:07:12 +01:00
mPatterns.append(patterns.at(i));
mPatternKinds.append(patternKinds.at(i));
if (patternKinds.at(i) == REGEX_PERL) {
const QByteArray& regexp = patterns.at(i).toUtf8();
int errorcode;
PCRE2_SIZE erroffset;
// PCRE2_UTF needed to run compile in UTF-8 mode
// PCRE2_UCP needed for \d, \w etc. to use Unicode properties:
QSharedPointer<pcre2_code> const re(pcre2_compile(reinterpret_cast<PCRE2_SPTR>(regexp.constData()), PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &erroffset, nullptr),
pcre2_code_deleter);
if (!re) {
PCRE2_UCHAR errorBuffer[256];
pcre2_get_error_message(errorcode, errorBuffer, sizeof(errorBuffer));
const char* error = reinterpret_cast<const char*>(errorBuffer);
if (mudlet::smDebugMode) {
TDebug(Qt::white, Qt::red) << "REGEX ERROR: failed to compile, reason:\n" << error << "\n" >> mpHost;
TDebug(Qt::red, Qt::gray) << TDebug::csmContinue << R"(in: ")" << regexp.constData() << "\"\n" >> mpHost;
}
setError(qsl("<b>%1</b>")
.arg(tr(R"(Error: in item %1, perl regex "%2" failed to compile, reason: "%3".)")
.arg(QString::number(i + 1), QString(regexp.constData()).toHtmlEscaped(), QString(error).toHtmlEscaped())));
state = false;
} else {
pcre2_jit_compile(re.data(), PCRE2_JIT_COMPLETE);
if (mudlet::smDebugMode) {
TDebug(Qt::white, Qt::darkGreen) << "[OK]: REGEX_COMPILE OK\n" >> mpHost;
}
}
mRegexMap[i] = re;
mTriggerContainsPerlRegex = true;
2009-04-09 21:42:11 +02:00
}
(release 30)bug fix report regexp errors correctly (#411) * BugFix: report regexp errors in TAlias correctly Fixes a long standing bug https://bugs.launchpad.net/mudlet/+bug/583584 Although original problem was with TAlias items (which use a regexp) to match against user keystrokes it also minded me to take a look at the behaviour of TTrigger items that had perl regexp type entries, and I have updated the error messages for those to also report the error details should there be any in a regexp. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> * BugFix: make TAlias report regexp compile errors to Debug console Although previous commit added error messages for failure to compile the regexp in the TAlias class instances to the editor window they did not show in the Debug Console if it was enabled - given that a successful message can be shown in such situations it can be misleading that everything is alright, even when it isn't. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> * Tweaks: revise formatting & revert some prior non-bugFixes Reverting commenting out of TAlias::compile() as it isn't a "bugfix". Added BOLD and BLUE formatting to Editor Error message for compilation of TAlias regexp. Reverting Lua related messages produced on the Central Debug Console during run of TAlias::compileAll() so that the wording stays the same as that produced for other Mudlet elements. Enhancements are intended in this area but they are not BugFixes so should not be aimed at this branch. Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2017-03-13 02:01:07 +00:00
if (patternKinds.at(i) == REGEX_LUA_CODE) {
std::string funcName;
std::stringstream func;
func << "trigger" << mID << "condition" << i;
funcName = func.str();
const QString code = qsl("function %1() %2\nend").arg(funcName.c_str(), patterns[i]);
QString error;
if (!mpLua->compile(code, error, QString::fromStdString(funcName))) {
setError(qsl("<b>%1</b>")
.arg(tr(R"(Error: in item %1, lua function "%2" failed to compile, reason: "%3".)").arg(QString::number(i + 1), patterns.at(i).toHtmlEscaped(), QString(error))));
state = false;
if (mudlet::smDebugMode) {
TDebug(Qt::white, Qt::red) << "LUA ERROR: failed to compile, reason:\n" << error << "\n" >> mpHost;
TDebug(Qt::red, Qt::gray) << TDebug::csmContinue << R"(in lua condition function: ")" << patterns.at(i) << "\"\n" >> mpHost;
}
} else {
mLuaConditionMap[i] = funcName;
}
}
(release 30)bug fix report regexp errors correctly (#411) * BugFix: report regexp errors in TAlias correctly Fixes a long standing bug https://bugs.launchpad.net/mudlet/+bug/583584 Although original problem was with TAlias items (which use a regexp) to match against user keystrokes it also minded me to take a look at the behaviour of TTrigger items that had perl regexp type entries, and I have updated the error messages for those to also report the error details should there be any in a regexp. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> * BugFix: make TAlias report regexp compile errors to Debug console Although previous commit added error messages for failure to compile the regexp in the TAlias class instances to the editor window they did not show in the Debug Console if it was enabled - given that a successful message can be shown in such situations it can be misleading that everything is alright, even when it isn't. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> * Tweaks: revise formatting & revert some prior non-bugFixes Reverting commenting out of TAlias::compile() as it isn't a "bugfix". Added BOLD and BLUE formatting to Editor Error message for compilation of TAlias regexp. Reverting Lua related messages produced on the Central Debug Console during run of TAlias::compileAll() so that the wording stays the same as that produced for other Mudlet elements. Enhancements are intended in this area but they are not BugFixes so should not be aimed at this branch. Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2017-03-13 02:01:07 +00:00
if (patternKinds[i] == REGEX_COLOR_PATTERN) {
int textAnsiFg = scmIgnored;
int textAnsiBg = scmIgnored;
// Decode the pattern string to the colour codes wanted:
TTrigger::decodeColorPatternText(patterns.at(i), textAnsiFg, textAnsiBg);
if (textAnsiBg == scmIgnored && textAnsiFg == scmIgnored) {
setError(qsl("<b>%1</b>")
.arg(tr("Error: in item %1, no colors to match were set - at least <i>one</i> of the foreground or background must not be <i>ignored</i>.")
.arg(QString::number(i + 1))));
state = false;
continue;
}
// The setupColorTrigger(...) method will push_back the created
// TColorTable instance if it is successful:
if (!setupColorTrigger(textAnsiFg, textAnsiBg)) {
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.emplace_back(nullptr);
state = false;
continue;
}
} else {
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.emplace_back(nullptr);
}
}
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
mOK_init = state;
2009-04-09 21:42:11 +02:00
return state;
2009-01-24 02:50:22 +01:00
}
bool TTrigger::match_perl(char* haystackC, const QString& haystack, int patternNumber, int posOffset, int lineNumber)
2009-01-24 02:50:22 +01:00
{
assert(mRegexMap.contains(patternNumber));
2010-03-18 16:07:12 +01:00
QSharedPointer<pcre2_code> const re = mRegexMap[patternNumber];
if (!re) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::white, Qt::red) << "ERROR:" >> mpHost;
TDebug(Qt::darkRed, Qt::darkGray) << TDebug::csmContinue << " the regex of trigger " << mName
<< " does not compile. Please correct the expression. This trigger will never match until it is fixed.\n"
>> mpHost;
}
return false; //regex compile error
}
2010-03-18 16:07:12 +01:00
const int haystackCLength = strlen(haystackC);
2010-03-18 16:07:12 +01:00
fix: trigger matching no longer allocates memory for every pattern on every line (#9852) #### Brief overview of PR changes/additions - `match_perl()` called `pcre2_match_data_create_from_pattern()` + `pcre2_match_data_free()` on every call: one heap allocation and free per Perl-regex pattern, per reachable trigger, per line of game text. - Cache one `match_data` per compiled pattern and reuse it across lines, in a `QSharedPointer` with a deleter to match how `mRegexMap` already owns its `pcre2_code`. Cleared alongside `mRegexMap` when patterns are recompiled, since each block is sized from its pattern's capture count. - Reuse is safe under re-entrancy: `processRegexMatch()` copies every capture out of the ovector into `captureList` before calling `execute()`, so a script that calls `feedTriggers()` and re-enters `match_perl()` on the same pattern cannot clobber an ovector still being read. #### Motivation for adding to Mudlet This is a regression, not a missed optimisation: before #8533 migrated the regex engine to PCRE2 the match results went into a stack array (`int ovector[MAX_CAPTURE_GROUPS]`), and the per-call heap allocation arrived unnoticed with PCRE2's API style. #### Other info (issues closed, discussion etc) Measured with `PipelineBenchmark` on macOS/arm64, Release, `-DUSE_SANITIZER=""`, using two binaries from one toolchain run in 24 interleaved ABBA pairs (alternating order, so run-order effects cancel): trigger throughput **+3.11%** (t=3.00), trigger overhead **-5.51%** (t=-2.13). The text-only control moved -0.92% (t=-0.26, 12/24 paired wins) i.e. no effect, which is the check that the trigger deltas are real. ASan must be off for this measurement since it instruments every malloc. **Test case:** behaviour-neutral, so the checks are for regressions. Perl-regex triggers with 2 and 3 capture groups firing on one line both return correct captures; editing a saved trigger's pattern to one with a different capture count then re-firing still returns correct captures (exercises cache invalidation); a trigger whose script calls `feedTriggers()` into a second Perl trigger still fires correctly (exercises re-entrancy). Verified against before/after builds on macOS, plus 6 trigger functional test suites. --------- Signed-off-by: Jay Howard <jay.patrick.howard@gmail.com>
2026-08-13 08:46:35 -05:00
QSharedPointer<pcre2_match_data>& matchData = mMatchDataMap[patternNumber];
if (!matchData) {
matchData.reset(pcre2_match_data_create_from_pattern(re.data(), nullptr), pcre2_match_data_deleter);
if (!matchData) {
return false;
}
}
fix: trigger matching no longer allocates memory for every pattern on every line (#9852) #### Brief overview of PR changes/additions - `match_perl()` called `pcre2_match_data_create_from_pattern()` + `pcre2_match_data_free()` on every call: one heap allocation and free per Perl-regex pattern, per reachable trigger, per line of game text. - Cache one `match_data` per compiled pattern and reuse it across lines, in a `QSharedPointer` with a deleter to match how `mRegexMap` already owns its `pcre2_code`. Cleared alongside `mRegexMap` when patterns are recompiled, since each block is sized from its pattern's capture count. - Reuse is safe under re-entrancy: `processRegexMatch()` copies every capture out of the ovector into `captureList` before calling `execute()`, so a script that calls `feedTriggers()` and re-enters `match_perl()` on the same pattern cannot clobber an ovector still being read. #### Motivation for adding to Mudlet This is a regression, not a missed optimisation: before #8533 migrated the regex engine to PCRE2 the match results went into a stack array (`int ovector[MAX_CAPTURE_GROUPS]`), and the per-call heap allocation arrived unnoticed with PCRE2's API style. #### Other info (issues closed, discussion etc) Measured with `PipelineBenchmark` on macOS/arm64, Release, `-DUSE_SANITIZER=""`, using two binaries from one toolchain run in 24 interleaved ABBA pairs (alternating order, so run-order effects cancel): trigger throughput **+3.11%** (t=3.00), trigger overhead **-5.51%** (t=-2.13). The text-only control moved -0.92% (t=-0.26, 12/24 paired wins) i.e. no effect, which is the check that the trigger deltas are real. ASan must be off for this measurement since it instruments every malloc. **Test case:** behaviour-neutral, so the checks are for regressions. Perl-regex triggers with 2 and 3 capture groups firing on one line both return correct captures; editing a saved trigger's pattern to one with a different capture count then re-firing still returns correct captures (exercises cache invalidation); a trigger whose script calls `feedTriggers()` into a second Perl trigger still fires correctly (exercises re-entrancy). Verified against before/after builds on macOS, plus 6 trigger functional test suites. --------- Signed-off-by: Jay Howard <jay.patrick.howard@gmail.com>
2026-08-13 08:46:35 -05:00
pcre2_match_data* match_data = matchData.data();
int rc = pcre2_match(re.data(), reinterpret_cast<PCRE2_SPTR>(haystackC), haystackCLength, 0, 0, match_data, nullptr);
2010-03-18 16:07:12 +01:00
if (rc < 0) {
return false;
}
processRegexMatch(haystackC, haystack, patternNumber, posOffset, re, haystackCLength, match_data, rc, lineNumber);
return true;
}
void TTrigger::processRegexMatch(const char* haystackC,
const QString& haystack,
int patternNumber,
int posOffset,
const QSharedPointer<pcre2_code>& re,
int haystackCLength,
pcre2_match_data* match_data,
int rc,
int lineNumber)
{
PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(match_data);
2010-03-18 16:07:12 +01:00
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::blue, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") matched.\n" >> mpHost;
}
int i = 0;
int numberOfCaptureGroups = 0;
std::list<std::string> captureList;
std::list<int> posList;
QMap<QString, QPair<int, int>> namePositions;
NameGroupMatches nameGroups;
for (i = 0; i < rc; i++) {
const char* substring_start = haystackC + ovector[2 * i];
const int substring_length = ovector[2 * i + 1] - ovector[2 * i];
2009-02-16 17:22:00 +01:00
std::string match;
if (substring_length < 1) {
captureList.push_back(match);
posList.push_back(-1);
continue;
}
const int utf16_pos = QString::fromUtf8(haystackC, ovector[2 * i]).length();
match.append(substring_start, substring_length);
captureList.push_back(match);
posList.push_back(utf16_pos + posOffset);
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::darkCyan, Qt::black) << "capture group #" << (i + 1) << " = " >> mpHost;
TDebug(Qt::darkMagenta, Qt::black) << TDebug::csmContinue << "<" << match.c_str() << ">\n" >> mpHost;
}
}
uint32_t namecount = 0;
uint32_t name_entry_size = 0;
PCRE2_SPTR tabptr = nullptr;
pcre2_pattern_info(re.data(), PCRE2_INFO_NAMECOUNT, &namecount);
2010-03-18 16:07:12 +01:00
if (namecount > 0) {
// Retrieves char table and entry size and extracts name of group and captures
pcre2_pattern_info(re.data(), PCRE2_INFO_NAMETABLE, &tabptr);
pcre2_pattern_info(re.data(), PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size);
for (uint32_t j = 0; j < namecount; ++j) {
const int n = (tabptr[0] << 8) | tabptr[1];
auto name =
QString::fromUtf8(reinterpret_cast<const char*>(&tabptr[2])).trimmed(); //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index)
tabptr += name_entry_size;
if (ovector[2 * n] == PCRE2_UNSET) { //NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
continue;
}
auto* substring_start = haystackC + ovector[2 * n]; //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index)
auto substring_length = ovector[2 * n + 1] - ovector[2 * n]; //NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
auto utf16_pos = QString::fromUtf8(haystackC, ovector[2 * n]).length(); //NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
auto capture = QString::fromUtf8(substring_start, substring_length);
nameGroups << qMakePair(name, capture);
namePositions.insert(name, qMakePair(utf16_pos + posOffset, static_cast<int>(capture.length())));
}
2010-03-18 16:07:12 +01:00
}
if (mIsColorizerTrigger || mFilterTrigger) {
numberOfCaptureGroups = captureList.size();
}
for (; mPerlSlashGOption;) {
uint32_t options = 0;
const PCRE2_SIZE start_offset = ovector[1];
2010-03-18 16:07:12 +01:00
if (ovector[0] == ovector[1]) {
if (ovector[0] >= static_cast<PCRE2_SIZE>(haystackCLength)) {
goto END;
2009-01-24 02:50:22 +01:00
}
options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
2009-01-24 02:50:22 +01:00
}
2010-03-18 16:07:12 +01:00
rc = pcre2_match(re.data(), reinterpret_cast<PCRE2_SPTR>(haystackC), haystackCLength, start_offset, options, match_data, nullptr);
2010-03-18 16:07:12 +01:00
if (rc == PCRE2_ERROR_NOMATCH) {
if (options == 0) {
break;
}
ovector[1] = start_offset + 1;
2010-03-18 16:07:12 +01:00
continue;
} else if (rc < 0) { // NOLINT(readability-else-after-return)
goto END;
}
for (i = 0; i < rc; i++) {
const char* substring_start = haystackC + ovector[2 * i];
const int substring_length = ovector[2 * i + 1] - ovector[2 * i];
2009-02-16 17:22:00 +01:00
std::string match;
if (substring_length < 1) {
captureList.push_back(match);
posList.push_back(-1);
continue;
}
const int utf16_pos = QString::fromUtf8(haystackC, ovector[2 * i]).length();
match.append(substring_start, substring_length);
captureList.push_back(match);
posList.push_back(utf16_pos + posOffset);
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::darkCyan, Qt::black) << "<regex mode: match all> capture group #" << (i + 1) << " = " >> mpHost;
TDebug(Qt::darkMagenta, Qt::black) << "<" << match.c_str() << ">\n" >> mpHost;
}
}
2010-03-18 16:07:12 +01:00
}
END: {
if (mIsColorizerTrigger) {
const int r1 = mBgColor.red();
const int g1 = mBgColor.green();
const int b1 = mBgColor.blue();
const int r2 = mFgColor.red();
const int g2 = mFgColor.green();
const int b2 = mFgColor.blue();
const int total = captureList.size();
TConsole* pC = mpHost->mpConsole;
if (Q_UNLIKELY(!pC)) {
return;
}
pC->deselect();
auto its = captureList.begin();
auto iti = posList.begin();
for (int position = 1; iti != posList.end(); ++iti, ++its, position++) {
const int begin = *iti;
const std::string& s = *its;
const int length = QString::fromStdString(s).size();
if (total > 1) {
// skip complete match in Perl /g option type of triggers
// to enable people to highlight capture groups if there are any
// otherwise highlight complete expression match
if (position % numberOfCaptureGroups != 1) {
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
}
}
} else {
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
}
}
}
pC->reset();
}
if (mIsMultiline) {
updateMultistates(patternNumber, captureList, posList, &nameGroups);
return;
}
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setCaptureGroups(captureList, posList);
pL->setCaptureNameGroups(nameGroups, namePositions);
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
if (captureList.size() > 1) {
const int total = captureList.size();
auto its = captureList.begin();
auto iti = posList.begin();
for (int filterPosition = 1; iti != posList.end(); ++iti, ++its, filterPosition++) {
int begin = *iti;
std::string& s = *its;
if (total > 1 && numberOfCaptureGroups > 0) {
// skip complete match in Perl /g option type of triggers
// to enable people to highlight capture groups if there are any
// otherwise highlight complete expression match
if (filterPosition % numberOfCaptureGroups != 1) {
filter(s, begin, lineNumber);
}
} else {
filter(s, begin, lineNumber);
}
}
}
}
return;
}
}
bool TTrigger::match_begin_of_line_substring(const QString& haystack, const QString& needle, int patternNumber, int posOffset, int lineNumber)
{
if (haystack.startsWith(needle)) {
processBeginOfLine(needle, patternNumber, posOffset, lineNumber);
return true;
}
return false;
}
void TTrigger::processBeginOfLine(const QString& needle, int patternNumber, int posOffset, int lineNumber)
{
std::list<std::string> captureList;
std::list<int> posList;
captureList.emplace_back(needle.toUtf8().constData());
posList.push_back(0 + posOffset);
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::darkCyan, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") matched.\n" >> mpHost;
}
if (mIsColorizerTrigger) {
const int r1 = mBgColor.red();
const int g1 = mBgColor.green();
const int b1 = mBgColor.blue();
const int r2 = mFgColor.red();
const int g2 = mFgColor.green();
const int b2 = mFgColor.blue();
TConsole* pC = mpHost->mpConsole;
if (Q_UNLIKELY(!pC)) {
return;
}
auto its = captureList.begin();
for (auto iti = posList.begin(); iti != posList.end(); ++iti, ++its) {
const int begin = *iti;
const std::string& s = *its;
const int length = QString::fromStdString(s).size();
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
}
}
pC->reset();
}
if (mIsMultiline) {
updateMultistates(patternNumber, captureList, posList);
return;
}
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setCaptureGroups(captureList, posList);
// call lua trigger function with number of matches and matches itselves as arguments
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
if (!captureList.empty()) {
filter(captureList.front(), posList.front(), lineNumber);
}
}
2009-01-24 02:50:22 +01:00
}
void TTrigger::updateMultistates(int regexNumber, std::list<std::string>& captureList, std::list<int>& posList, const NameGroupMatches* nameMatches)
2009-01-24 02:50:22 +01:00
{
if (regexNumber == 0) {
// automatically set to #1
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
auto pCondition = std::make_unique<TMatchState>(mPatterns.size(), mConditionLineDelta);
auto* pConditionRaw = pCondition.get();
mConditionMap[pConditionRaw] = std::move(pCondition);
pConditionRaw->multiCaptureList.push_back(captureList);
pConditionRaw->multiCapturePosList.push_back(posList);
if (nameMatches) {
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
pConditionRaw->nameCaptures.push_back(*nameMatches);
} else {
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
pConditionRaw->nameCaptures.push_back(QVector<QPair<QString, QString>>());
}
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::darkYellow, Qt::black) << "match state " << mConditionMap.size() << "/" << mConditionMap.size() << " condition #" << regexNumber << "=true (" << regexNumber << "/"
<< mPatterns.size() << ") regex=" << mPatterns[regexNumber] << "\n"
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
>> mpHost;
}
} else {
int k = 0;
for (auto& matchStatePair : mConditionMap) {
2009-04-03 01:33:48 +02:00
k++;
if (matchStatePair.second->nextCondition() == regexNumber) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::darkYellow, Qt::black) << "match state " << k << "/" << mConditionMap.size() << " condition #" << regexNumber << "=true (" << regexNumber << "/" << mPatterns.size()
<< ") regex=" << mPatterns[regexNumber] << "\n"
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
>> mpHost;
}
matchStatePair.second->conditionMatched();
matchStatePair.second->multiCaptureList.push_back(captureList);
matchStatePair.second->multiCapturePosList.push_back(posList);
if (nameMatches != nullptr) {
matchStatePair.second->nameCaptures.push_back(*nameMatches);
} else {
matchStatePair.second->nameCaptures.push_back(QVector<QPair<QString, QString>>());
}
2009-01-24 02:50:22 +01:00
}
2009-04-03 01:33:48 +02:00
}
}
}
void TTrigger::filter(std::string& capture, int& posOffset, int lineNumber)
2009-04-28 02:52:30 +02:00
{
if (capture.empty()) {
return;
}
const QString text = QString::fromStdString(capture);
for (auto& trigger : *mpMyChildrenList) {
trigger->match(capture.data(), text, lineNumber, posOffset);
2009-04-28 02:52:30 +02:00
}
}
2018-07-11 20:39:50 +02:00
int TTrigger::getExpiryCount() const
{
return mExpiryCount;
}
void TTrigger::setExpiryCount(int expiryCount)
{
mExpiryCount = expiryCount;
}
bool TTrigger::match_substring(const QString& haystack, const QString& needle, int patternNumber, int posOffset, int lineNumber)
2009-04-03 01:33:48 +02:00
{
const int where = haystack.indexOf(needle);
if (where != -1) {
processSubstringMatch(haystack, needle, patternNumber, posOffset, where, lineNumber);
return true;
}
return false;
}
void TTrigger::processSubstringMatch(const QString& haystack, const QString& needle, int regexNumber, int posOffset, int where, int lineNumber)
{
std::list<std::string> captureList;
std::list<int> posList;
captureList.emplace_back(needle.toUtf8().constData());
posList.push_back(where + posOffset);
if (mPerlSlashGOption) {
while ((where = haystack.indexOf(needle, where + 1)) != -1) {
captureList.emplace_back(needle.toUtf8().constData());
posList.push_back(where + posOffset);
2009-01-24 02:50:22 +01:00
}
}
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::cyan, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(regexNumber) << ") matched.\n" >> mpHost;
}
if (mIsColorizerTrigger) {
const int r1 = mBgColor.red();
const int g1 = mBgColor.green();
const int b1 = mBgColor.blue();
const int r2 = mFgColor.red();
const int g2 = mFgColor.green();
const int b2 = mFgColor.blue();
TConsole* pC = mpHost->mpConsole;
if (Q_UNLIKELY(!pC)) {
return;
}
pC->deselect();
auto its = captureList.begin();
for (auto iti = posList.begin(); iti != posList.end(); ++iti, ++its) {
const int begin = *iti;
const std::string& s = *its;
const int length = QString::fromStdString(s).size();
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
}
}
pC->reset();
}
if (mIsMultiline) {
updateMultistates(regexNumber, captureList, posList);
return;
}
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setCaptureGroups(captureList, posList);
// call lua trigger function with number of matches and matches itselves as arguments
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
if (!captureList.empty()) {
filter(captureList.front(), posList.front(), lineNumber);
}
2010-03-18 16:07:12 +01:00
}
2009-01-24 02:50:22 +01:00
}
bool TTrigger::match_color_pattern(int line, int patternNumber, int posOffset, int length)
2009-05-22 16:37:38 +02:00
{
if (patternNumber >= mColorPatternList.size()) {
return false;
}
if (line == -1) {
return false;
}
2009-05-22 16:37:38 +02:00
bool canExecute = false;
std::list<std::string> captureList;
std::list<int> posList;
if (line >= static_cast<int>(mpHost->mpConsole->buffer.buffer.size())) {
return false;
}
std::deque<TChar>& bufferLine = mpHost->mpConsole->buffer.buffer[line];
const QString& lineBuffer = mpHost->mpConsole->buffer.lineBuffer[line];
// Match against the colors as they arrived from the game, not as already
// recolored by other triggers or scripts earlier in this trigger pass;
// text inserted mid-pass has no game original so it is read live:
const std::deque<TChar>* pPassLine = mpHost->mpConsole->buffer.preTriggerPassLine(line);
// Filter ("only pass matches") parents hand children just the matched
// capture, so restrict the scan to that window; for top-level triggers
// the window covers the whole line:
const int start = qBound(0, posOffset, static_cast<int>(bufferLine.size()));
const int end = qBound(start, posOffset + length, static_cast<int>(bufferLine.size()));
int pos = start;
2009-06-04 10:27:08 +02:00
int matchBegin = -1;
bool matching = false;
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
TColorTable* pCT = mColorPatternList[patternNumber].get();
if (!pCT) {
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
return false; // no color pattern created
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
if (pCT->ansiBg == scmIgnored && pCT->ansiFg == scmIgnored) {
// BOTH the foreground AND the background colors are set to "ignore"
// so this is not an active color trigger setup - so ignore it
return false; // no color settings to match against
}
for (auto it = bufferLine.begin() + start; pos < end; ++it, ++pos) {
const TChar& character = (pPassLine && pos < static_cast<int>(pPassLine->size())) ? (*pPassLine)[pos] : *it;
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// This now allows matching against the current default colours (-1) and
// allows ONE of the foreground or background to NOT be considered (-2)
// Ideally we should base the matching on only the ANSI code but not
// all parts of the text come from the Server and can be determined to
// have come from a decoded ANSI code number:
if (((pCT->ansiFg == scmIgnored) || ((pCT->ansiFg == scmDefault) && mpHost->mpConsole->mFgColor == character.foreground()) || (pCT->mFgColor == character.foreground()))
&& ((pCT->ansiBg == scmIgnored) || ((pCT->ansiBg == scmDefault) && mpHost->mpConsole->mBgColor == character.background()) || (pCT->mBgColor == character.background()))) {
if (matchBegin == -1) {
2009-06-04 10:27:08 +02:00
matchBegin = pos;
}
2009-06-04 10:27:08 +02:00
matching = true;
} else {
2009-06-04 10:27:08 +02:00
matching = false;
2009-05-22 16:37:38 +02:00
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
if ((!matching) || (matching && (pos + 1 >= end))) {
if (matchBegin > -1) {
2010-03-18 16:07:12 +01:00
std::string got;
if (matching) {
got = lineBuffer.mid(matchBegin, pos - matchBegin + 1).toUtf8().constData();
} else {
got = lineBuffer.mid(matchBegin, pos - matchBegin).toUtf8().constData();
}
captureList.push_back(got);
posList.push_back(matchBegin);
2009-06-04 10:27:08 +02:00
matchBegin = -1;
canExecute = true;
matching = false;
2009-05-22 16:37:38 +02:00
}
}
2009-06-04 10:27:08 +02:00
}
if (canExecute) {
processColorPattern(patternNumber, captureList, posList, line);
return true;
}
return false;
}
void TTrigger::processColorPattern(int patternNumber, std::list<std::string>& captureList, std::list<int>& posList, int lineNumber)
{
if (mIsColorizerTrigger) {
const int r1 = mBgColor.red();
const int g1 = mBgColor.green();
const int b1 = mBgColor.blue();
const int r2 = mFgColor.red();
const int g2 = mFgColor.green();
const int b2 = mFgColor.blue();
TConsole* pC = mpHost->mpConsole;
if (Q_UNLIKELY(!pC)) {
return;
}
pC->deselect();
auto its = captureList.begin();
for (auto iti = posList.begin(); iti != posList.end(); ++iti, ++its) {
const int begin = *iti;
// qDebug() << "TTrigger::match_color_pattern(" << line << "," << patternNumber << ") INFO - match found: " << (*its).c_str() << " size is:" << (*its).size();
const std::string& s = *its;
const int length = QString::fromStdString(s).size();
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
2009-05-22 16:37:38 +02:00
}
}
pC->reset();
}
if (mIsMultiline) {
updateMultistates(patternNumber, captureList, posList);
return;
}
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setCaptureGroups(captureList, posList);
// call lua trigger function with number of matches and matches itselves as arguments
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
if (!captureList.empty()) {
auto it1 = captureList.begin();
auto it2 = posList.begin();
for (; it1 != captureList.end(); it1++, it2++) {
filter(*it1, *it2, lineNumber);
2009-05-22 16:37:38 +02:00
}
}
}
}
bool TTrigger::match_line_spacer(int patternNumber)
{
if (mIsMultiline) {
int k = 0;
2010-03-15 09:37:16 +01:00
for (auto& matchStatePair : mConditionMap) {
k++;
if (matchStatePair.second->nextCondition() == patternNumber) {
if (matchStatePair.second->lineSpacerMatch(mPatterns.value(patternNumber).toInt())) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::yellow, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") condition #" << patternNumber << "=true " >> mpHost;
TDebug(Qt::darkYellow, Qt::black) << TDebug::csmContinue << "match state " << k << "/" << mConditionMap.size() << " condition #" << patternNumber << "=true ("
<< patternNumber + 1 << "/" << mPatterns.size() << ") line spacer=" << mPatterns.value(patternNumber) << "lines\n"
>> mpHost;
}
matchStatePair.second->conditionMatched();
std::list<std::string> const captureList;
std::list<int> const posList;
matchStatePair.second->multiCaptureList.push_back(captureList);
matchStatePair.second->multiCapturePosList.push_back(posList);
matchStatePair.second->nameCaptures.push_back(QVector<QPair<QString, QString>>());
}
}
}
}
2010-12-28 23:31:03 +01:00
return true; //line spacers don't make sense outside of AND triggers -> ignore them
}
bool TTrigger::match_lua_code(int patternNumber)
{
if (mLuaConditionMap.find(patternNumber) == mLuaConditionMap.end()) {
return false;
}
if (mpLua->callConditionFunction(mLuaConditionMap[patternNumber], mName)) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::yellow, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") matched.\n" >> mpHost;
}
if (mIsMultiline) {
2009-04-03 01:33:48 +02:00
std::list<std::string> captureList;
std::list<int> posList;
updateMultistates(patternNumber, captureList, posList);
2009-04-03 01:33:48 +02:00
return true;
}
execute();
return true;
}
return false;
}
bool TTrigger::match_prompt(int patternNumber)
{
if (mpHost->mpConsole->mIsPromptLine) {
processPromptMatch(patternNumber);
return true;
}
return false;
}
void TTrigger::processPromptMatch(int patternNumber)
2009-01-24 02:50:22 +01:00
{
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::yellow, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") matched.\n" >> mpHost;
}
if (mIsMultiline) {
2009-04-03 01:33:48 +02:00
std::list<std::string> captureList;
std::list<int> posList;
updateMultistates(patternNumber, captureList, posList);
return;
}
execute();
}
bool TTrigger::match_exact_match(const QString& haystack, const QString& needle, int patternNumber, int posOffset, int lineNumber)
{
fix: exact-match triggers no longer copy every line they check (#9853) #### Brief overview of PR changes/additions - `match_exact_match()` did `QString text = haystack;` then chopped a trailing newline. The assignment is copy-on-write and cheap, but `chop()` mutates, forcing the detach: a heap allocation plus a full character copy of the line. - The newline is always present - `TMainConsole::runTriggers()` appends one to every line before dispatch (`TMainConsole.cpp:1570`) - so the chop always fires and the copy always happens, once per exact-match pattern, per reachable trigger, per line of game text. - Use a `QStringView`. Chopping a view moves only its own end pointer, so nothing is allocated, and the comparison against the needle is unchanged. Both chop one UTF-16 code unit, so behaviour is identical for every input. #### Motivation for adding to Mudlet Removes a per-line heap allocation and line copy from the trigger matching path, which runs for every line of game text. #### Other info (issues closed, discussion etc) Measured with `PipelineBenchmark` on macOS/arm64, Release, `-DUSE_SANITIZER=""`, two binaries from one toolchain run in 24 interleaved ABBA pairs so run-order effects cancel: trigger throughput **+3.28%** (t=6.41), trigger overhead **-6.37%** (t=-4.94). The text-only control moved +0.23% (t=-0.56, 12/24 paired wins), i.e. no effect, which is the check that the trigger deltas are real. Worth stating plainly: the stock benchmark corpus contains **no** exact-match patterns, so `match_exact_match()` is never entered by it. Twelve were added locally purely to measure this. The gain therefore scales with how many exact-match patterns a profile actually has, and is zero for a profile with none. **Test case:** behaviour-neutral, so the checks are for regressions around where the chop lands. Exact-match triggers fire correctly on a plain ASCII line, on a line with an accented character, on one with an em dash, and on one containing an emoji (a surrogate pair, i.e. two UTF-16 code units - the case most likely to expose a code-unit-based chop). A line with trailing whitespace before the newline correctly does *not* match. Verified against before/after builds on macOS, plus 5 trigger functional test suites. --------- Signed-off-by: Jay Howard <jay.patrick.howard@gmail.com>
2026-08-13 08:47:25 -05:00
QStringView text(haystack);
if (text.endsWith(QChar('\n'))) {
text.chop(1);
}
if (text == needle) {
processExactMatch(needle, patternNumber, posOffset, lineNumber);
return true;
}
return false;
}
void TTrigger::processExactMatch(const QString& needle, int patternNumber, int posOffset, int lineNumber)
{
std::list<std::string> captureList;
std::list<int> posList;
captureList.emplace_back(needle.toUtf8().constData());
posList.push_back(0 + posOffset);
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
TDebug(Qt::yellow, Qt::black) << "Trigger name=" << mName << "(" << mPatterns.value(patternNumber) << ") matched.\n" >> mpHost;
}
if (mIsColorizerTrigger) {
const int r1 = mBgColor.red();
const int g1 = mBgColor.green();
const int b1 = mBgColor.blue();
const int r2 = mFgColor.red();
const int g2 = mFgColor.green();
const int b2 = mFgColor.blue();
TConsole* pC = mpHost->mpConsole;
if (Q_UNLIKELY(!pC)) {
return;
}
auto its = captureList.begin();
for (auto iti = posList.begin(); iti != posList.end(); ++iti, ++its) {
const int begin = *iti;
const std::string& s = *its;
const int length = QString::fromStdString(s).size();
pC->selectSection(begin, length);
if (mBgColor != QColorConstants::Transparent) {
pC->setBgColor(r1, g1, b1, 255);
}
if (mFgColor != QColorConstants::Transparent) {
pC->setFgColor(r2, g2, b2);
}
}
pC->reset();
}
if (mIsMultiline) {
updateMultistates(patternNumber, captureList, posList);
return;
}
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setCaptureGroups(captureList, posList);
// call lua trigger function with number of matches and matches themselves as arguments
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
if (!captureList.empty()) {
filter(captureList.front(), posList.front(), lineNumber);
}
2010-03-18 16:07:12 +01:00
}
2009-01-24 02:50:22 +01:00
}
// haystackC: string to match as a char*
// haystack: string to match as a QString
// line: line number in the buffer
// posOffset: position in the line to start matching from; used by child triggers
bool TTrigger::match(char* haystackC, const QString& haystack, int line, int posOffset)
2009-01-24 02:50:22 +01:00
{
// Guard against re-entrancy: cleanup may have deleted this trigger while
// match() was still on the call stack
if (!mpMyChildrenList) {
qWarning() << "TTrigger::match() called on destroyed trigger - ID:" << mID << "Name:" << mName;
return false;
}
2009-01-24 02:50:22 +01:00
bool ret = false;
if (isActive()) {
if (mIsLineTrigger) {
if (--mStartOfLineDelta < 0) {
2009-02-16 17:22:00 +01:00
execute();
if (--mLineDelta <= 0) {
deactivate();
mpHost->getTriggerUnit()->markCleanup(this);
}
2009-01-24 02:50:22 +01:00
return true;
}
return false;
}
2010-03-18 16:07:12 +01:00
if (haystack.isEmpty()) {
return false;
}
2009-05-22 16:37:38 +02:00
2009-02-11 02:42:27 +01:00
bool conditionMet = false;
2009-05-22 16:37:38 +02:00
2009-04-03 01:33:48 +02:00
int highestCondition = 0;
if (mIsMultiline) {
for (auto& matchStatePair : mConditionMap) {
matchStatePair.second->newLineArrived();
const int next = matchStatePair.second->nextCondition();
if (next > highestCondition) {
2009-04-03 01:33:48 +02:00
highestCondition = next;
}
2009-01-24 02:50:22 +01:00
}
2009-02-11 02:42:27 +01:00
}
const int size = mPatternKinds.size();
for (int patternNumber = 0;; patternNumber++) {
if (patternNumber >= size) {
break;
}
ret = false;
switch (mPatternKinds.value(patternNumber)) {
case REGEX_SUBSTRING:
ret = match_substring(haystack, mPatterns.at(patternNumber), patternNumber, posOffset, line);
break;
case REGEX_PERL:
ret = match_perl(haystackC, haystack, patternNumber, posOffset, line);
break;
case REGEX_BEGIN_OF_LINE_SUBSTRING:
ret = match_begin_of_line_substring(haystack, mPatterns.at(patternNumber), patternNumber, posOffset, line);
break;
case REGEX_EXACT_MATCH:
ret = match_exact_match(haystack, mPatterns.at(patternNumber), patternNumber, posOffset, line);
break;
case REGEX_LUA_CODE:
ret = match_lua_code(patternNumber);
break;
case REGEX_LINE_SPACER:
ret = match_line_spacer(patternNumber);
break;
case REGEX_COLOR_PATTERN:
// for a filter child the haystack is just the parent's capture,
// so its length bounds the color scan window on that line
ret = match_color_pattern(line, patternNumber, posOffset, static_cast<int>(haystack.length()));
break;
case REGEX_PROMPT:
ret = match_prompt(patternNumber);
break;
2009-01-24 02:50:22 +01:00
}
// policy: one match is enough to fire on OR-trigger, but in the case of
// an AND-trigger all conditions have to be met in order to fire the trigger
if (!mIsMultiline) {
if (ret) {
2009-02-11 02:42:27 +01:00
conditionMet = true;
mKeepFiring = mStayOpen;
2010-03-18 16:07:12 +01:00
break;
2009-01-24 02:50:22 +01:00
}
} else {
if ((!ret) && (patternNumber >= highestCondition)) {
break;
}
2009-04-03 01:33:48 +02:00
}
2009-01-24 02:50:22 +01:00
}
2010-03-18 16:07:12 +01:00
2009-01-24 02:50:22 +01:00
// in the case of multiline triggers: check our state
if (mIsMultiline) {
2010-03-18 16:07:12 +01:00
int k = 0;
2009-02-11 02:42:27 +01:00
conditionMet = false; //invalidate conditionMet as it has no meaning for multiline triggers
std::list<TMatchState*> removeList;
2010-03-18 16:07:12 +01:00
for (auto& matchStatePair : mConditionMap) {
2009-02-11 02:42:27 +01:00
k++;
if (matchStatePair.second->isComplete()) {
mKeepFiring = mStayOpen;
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
2021-08-22 08:01:05 +02:00
TDebug(Qt::yellow, Qt::darkMagenta) << "multiline trigger name=" << mName << " *FIRES* all conditions are fulfilled. Executing script.\n" >> mpHost;
}
removeList.push_back(matchStatePair.first);
conditionMet = true;
TLuaInterpreter* pL = mpHost->getLuaInterpreter();
pL->setMultiCaptureGroups(matchStatePair.second->multiCaptureList, matchStatePair.second->multiCapturePosList, matchStatePair.second->nameCaptures);
execute();
pL->clearCaptureGroups();
if (mFilterTrigger) {
std::list<std::list<std::string>> multiCaptureList;
multiCaptureList = matchStatePair.second->multiCaptureList;
if (!multiCaptureList.empty()) {
for (auto mit = multiCaptureList.begin(); mit != multiCaptureList.end(); mit++, k++) {
const int total = (*mit).size();
auto its = (*mit).begin();
for (int i = 1; its != (*mit).end(); ++its, i++) {
std::string s = *its;
int p = 0;
// multiline captures may come from earlier lines, so no
// single line number applies here
if (total > 1) {
if (i % total != 1) {
filter(s, p, -1);
}
} else {
filter(s, p, -1);
}
}
}
}
}
2009-01-24 02:50:22 +01:00
}
2010-03-18 16:07:12 +01:00
if (!matchStatePair.second->newLine()) {
removeList.push_back(matchStatePair.first);
2009-01-24 02:50:22 +01:00
}
}
for (auto& matchState : removeList) {
if (mConditionMap.find(matchState) != mConditionMap.end()) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
2021-08-22 08:01:05 +02:00
TDebug(Qt::darkBlue, Qt::black) << "removing condition from condition table.\n" >> mpHost;
2009-11-19 19:21:55 +01:00
}
mConditionMap.erase(matchState);
}
2009-01-24 02:50:22 +01:00
}
}
2010-03-18 16:07:12 +01:00
2009-05-22 16:37:38 +02:00
2009-02-11 02:42:27 +01:00
// definition trigger chain: a folder is part of a trigger chain if it has a regex defined
// a trigger chain only lets data pass if the condition matches or in case of multiline all
2021-08-22 08:01:05 +02:00
// all conditions are fulfilled
2009-02-11 02:42:27 +01:00
//
// a folder can also be a simple structural element in which case all data passes through
// if at least one regex is defined a folder is considered a trigger chain otherwise a structural element
if (!mFilterTrigger) {
if (conditionMet || (mPatterns.empty())) {
for (auto trigger : *mpMyChildrenList) {
ret = trigger->match(haystackC, haystack, line, posOffset);
if (ret) {
conditionMet = true;
}
2009-04-28 02:52:30 +02:00
}
2009-02-11 02:42:27 +01:00
}
2009-01-24 02:50:22 +01:00
}
2009-11-27 23:12:12 +01:00
if ((mKeepFiring > 0) && (!conditionMet)) {
2009-11-27 23:12:12 +01:00
mKeepFiring--;
if ((mKeepFiring == mStayOpen) || (mpMyChildrenList->empty())) {
2009-11-27 23:12:12 +01:00
execute();
}
for (auto trigger : *mpMyChildrenList) {
ret = trigger->match(haystackC, haystack, line, posOffset);
if (ret) {
conditionMet = true;
}
2009-11-27 23:12:12 +01:00
}
return true;
}
2018-07-11 20:39:50 +02:00
if (conditionMet && mExpiryCount > -1) {
mExpiryCount--;
if (mExpiryCount == 0) {
infrastructure: trim the comments left behind by two merged QA fixes (#9708) #### Brief overview of PR changes/additions - Comment-only. `git diff origin/development...HEAD` changes no statement, expression or declaration - every added and removed line is a comment. 238 comment lines become 98. - Applies the house standard to the comments added by "fix: a trigger that re-creates itself freezes Mudlet" (#9697) and "Fix user key bindings on Ctrl+1 to Ctrl+9 and Ctrl+Tab" (#9703): no historical passages, and the rest cut to what a reader cannot derive from the code. - Corrects four claims that were wrong, two of them inherited from those PRs: a fires-per-line measurement taken with a smaller budget than the one that shipped, an over-general note on `shortcutInstalledFor()`, a `KeyUnit::disableKey()` note that had the mechanism backwards, and a test comment crediting the `isEmpty()` guard for a result it does not produce. #### Motivation for adding to Mudlet Both PRs merged while their comment-reduction pass was still in flight, so the trim never landed with them. #### Other info (issues closed, discussion etc) The gotchas worth keeping survive in shorter form: why the same-line creation budget is counted per pass rather than sharing the `feedTriggers()` depth counter, why permanent triggers get `deactivate()` and not `setIsActive(false)`, why `mCleanupSet` rather than the deactivation is what stops `enableTrigger()` resurrecting a spent trigger, that `QShortcutMap` retries with consumed modifiers stripped, and the `Key_Backtab` versus `Shift+Tab` spelling. The matching trim for "fix: stop treating long-time Mudlet users as brand new players" (#9695) already landed separately as #9707, so it is not repeated here. No demo video: a comment-only change is not observable on screen. **Test case:** `ctest` in the build directory - 79/80, with `TelnetBenchmark` timing out only under parallel load (31s standalone against a 60s limit) on a path this PR does not touch. `TriggerSameLineMatchTest`, `UnitDeferredDeleteTest`, `ProfileSwitchShortcutTest` and `ExperiencedPlayerGateTest` all pass. Assisted-by: Claude:claude-opus-5
2026-08-06 17:43:35 +02:00
// The delete is deferred to the end of the outermost pass, so an
// expired trigger left active would fire again from any pass that
// re-enters meanwhile. What stops enableTrigger() resurrecting it
// in that window is the markCleanup() below, not the deactivation:
// enableTrigger() skips anything in mCleanupSet.
Fix temporary trigger/alias/key/timer cleanup evicting same-named items (#9682) #### Brief overview of PR changes/additions - An expired trigger is deactivated before it is queued for deletion, so a nested `feedTriggers()` pass cannot fire it again while the deferred delete is still pending. - Deleting a temporary trigger, alias, key or timer unlinks only that item from the by-name lookup table instead of every item filed under the same name, and `killAlias()`/`killKey()`/`killTimer()` scan past a same-named item they cannot kill rather than report failure over it. - `AliasUnit` and `KeyUnit` gain the double-free guards `TriggerUnit` and `TimerUnit` already had; `stopAllNamedTriggers()` and `IDMgr:emergencyStop()` now stop named regex triggers too. #### Motivation for adding to Mudlet The four lookup tables are `QMultiMap`s, so names are not unique, but the temporary-item branch used the single-argument `remove(key)` and evicted live same-named items with it: a permanent trigger could stay alive yet become invisible to `enableTrigger()`, `killTrigger()` and `exists()` for the rest of the session. The kill-by-name asymmetry is the same defect one level up - a permanent item restored from the profile precedes this session's temporaries in the root node list, so it stranded the temporary behind it. #### Other info (issues closed, discussion etc) Closes #9646, closes #9648, closes #9649, closes #9650 Test case: `permRegexTrigger("Health", "", {"^permanent$"}, [[echo("permanent fired\n")]])`, then `tempComplexRegexTrigger("Health", "^temp$", [[]], 0,0,0,0,0,0,0,0,0,0)`, `killTrigger("Health")` and `feedTriggers("permanent\n")` - `exists("Health", "trigger")` still finds the permanent trigger. New coverage: `test/functional_tests/UnitDeferredDeleteTest.cpp` (17 cases across all four units) plus additions to `Trigger_spec.lua`, `Alias_spec.lua`, `KeyBinds_spec.lua` and `IDManager_spec.lua`, three of which were `pending()` markers for these bugs. Review turned up an adjacent defect deliberately **not** fixed here: expiry is accounted for after `execute()` runs, so a trigger whose *own* script re-feeds the matching line overshoots its `expireAfter`. Fixing that means moving the expiry accounting ahead of `execute()` while keeping the "return true to extend" contract, so it is left for a follow-up and recorded as a `pending()` spec in `Trigger_spec.lua`. Assisted-by: Claude:claude-opus-5
2026-08-05 19:55:28 +02:00
setIsActive(false);
2018-07-11 20:39:50 +02:00
mpHost->getTriggerUnit()->markCleanup(this);
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
// FIXME: This message is translated - but most other TDebug ones are not!
TDebug(Qt::yellow, Qt::darkMagenta) << qsl("%1\n").arg(tr("Trigger name=%1 expired.").arg(mName)) >> mpHost;
2018-07-11 20:39:50 +02:00
}
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
} else if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
// FIXME: This message is translated - but most other TDebug ones are not!
Fix: clean up comments and related translation things (#8914) #### Brief overview of PR changes/additions Removes the `*`s in all but the first line of a multi-line translation comment that explains to the translators details of the Engineering English text in the source code. Whilst beginning each new line with an `*` can happen automagically in the Qt Creator as a result of the "Enable Doxygen Blocks" and "Add leading asterisks" options (in "Preferences" -> "Text Editor" -> "Documentation Comments") these are not always stripped out by the `lupdate` utility that generates the `mudlet.ts` file. Removes remaining `""` and replaces with `nullptr` any second arguments to `QObject::tr(...)` where a third argument is needed for the quantity for "numerus" (quantity dependent) translatable texts. Removes some, now obsolete, Windows specific code that identified if a 32-Bit version of Mudlet was being run in a 64-Bit Operating System. Since we no longer can produce such 32-Bit code it is now just cruft. Revises some quantity dependent code in `./src/dlgPackManager.cpp` so that only the zero cases are handled differently - in one place this means the conversion of a `.length() > 0` to an inverted `.isEmpty()` - and in three other places where a zero or one case was handled differently to the more than one case. #### Motivation for adding to Mudlet Improve the code quality and/or the situation for our translators. #### Other info (issues closed, discussion etc) Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2026-02-07 15:26:09 +00:00
TDebug(Qt::yellow, Qt::darkMagenta) << qsl("%1\n").arg(tr("Trigger name=%1 will fire %n more time(s).", nullptr, mExpiryCount).arg(mName)) >> mpHost;
2018-07-11 20:39:50 +02:00
}
}
2009-11-27 23:12:12 +01:00
2009-02-11 02:42:27 +01:00
return conditionMet;
2009-01-24 02:50:22 +01:00
}
return false;
}
bool TTrigger::checkIfNew()
{
return mIsNew;
}
void TTrigger::unmarkAsNew()
{
mIsNew = false;
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// This NOW uses proper ANSI numbers
// A TColorTable is a simple struct that stores four values, the two given ANSI
// colors for foreground and background (proper ANSI indexes) and what they look
// like give the current Host settings (the first 16 ANSI ones and the default
// fore and background colors can be changed by the user and since OSC P/R
2021-08-22 08:01:05 +02:00
// support has been implemented - by the MUD Server!)
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
std::unique_ptr<TColorTable> TTrigger::createColorPattern(int ansiFg, int ansiBg)
{
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
/*
* OLD Mudlet simplified ANSI color codes
* -> proper ANSI numbers
* ---------------------------------------------
* 0 default text color -> (-1 special value!)
* 1 light black -> 8
* 2 dark black -> 0
* 3 light red -> 9
* 4 dark red -> 1
* 5 light green -> 10
* 6 dark green -> 2
* 7 light yellow -> 11
* 8 dark yellow -> 3
* 9 light blue -> 12
* 10 dark blue -> 4
* 11 light magenta -> 13
* 12 dark magenta -> 5
* 13 light cyan -> 14
* 14 dark cyan -> 6
* 15 light white -> 15
* 16 dark white -> 7
*/
const QColor fgColor = mpHost->getAnsiColor(ansiFg, false);
const QColor bgColor = mpHost->getAnsiColor(ansiBg, true);
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// If BOTH ansiFg AND ansiBg are scmIgnored then the color pattern is
// totally unset
if (!(fgColor.isValid() || bgColor.isValid())) {
return nullptr;
}
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
auto pCT = std::unique_ptr<TColorTable>(new (std::nothrow) TColorTable);
if (!pCT) {
return nullptr;
}
pCT->ansiBg = ansiBg;
pCT->ansiFg = ansiFg;
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
pCT->mBgColor = bgColor;
pCT->mFgColor = fgColor;
return pCT;
}
bool TTrigger::setupColorTrigger(int ansiFg, int ansiBg)
{
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
auto pCT = createColorPattern(ansiFg, ansiBg);
if (!pCT) {
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// This can be caused by both ansiFg and ansiBg being scmIgnored
return false;
}
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.emplace_back(std::move(pCT));
return true;
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// The numbers here are NOW the proper ANSI colour codes (0 to 255)
// or scmDefault for default fore/background or scmIgnored for ignored
bool TTrigger::setupTmpColorTrigger(int ansiFg, int ansiBg)
{
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
auto pCT = createColorPattern(ansiFg, ansiBg);
if (!pCT) {
return false;
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
Infrastructure: remove unneeded control from trigger editor (#7505) #### Brief overview of PR changes/additions Simplify and improve the "trigger" editor part of the "Editor" by combining/removing some group boxes and making a third one not have a check-box. Also move them all from the bottom of the left to the right side of that area and improve the behaviour as the splitter for the right side is adjusted. #### Motivation for adding to Mudlet Improving the UI - helping to make the controls a bit more intuitive. #### Other info (issues closed, discussion etc) Having a QSpinBox to control the "condition line" delta for AND/Multi-line triggers as well as placing it in a checkable group-box to enable it is more complex than it needs to be. This PR removes the checkbox and instead uses the ability of a `QComboBox` to have a "special value" which it presents different - in this case to report the trigger as an OR/Multi-item type trigger. Having done this I realised that it and the other two items at the bottom of the left side of the "triggers" editor could be simplified further and all moved to the right side. Then I had to tweak the code that showed/hid the right and bottom widgets (since the bottom ones had gone). Finally I put in code to disable the "OR multi-item"/"AND multi-line" control when there is less than two "items" in the trigger. Also: * rename `(QWidget*) dlgTriggerEditor::HpatternList` ==> `dlgTriggerEditor::mpWidget_triggerItems` * convert the - not used as a button - `pushButton_prompt` from a `QPushButton` to a `QLabel` - and make it be enabled when GA/EoRs are detected - as well as changing the text as before. This was prompted by working on the fix for #7480.
2024-11-04 06:55:05 +00:00
// createColorPatternText(...) now returns an empty string if BOTH color
// codes are the scmIgnored ones:
mPatterns << createColorPatternText(ansiFg, ansiBg);
mPatternKinds << REGEX_COLOR_PATTERN;
improve: improve memory safety by using smart pointers (#9239) ### Refactor: replace raw pointer ownership with smart pointers across core subsystems #### Brief overview of PR changes/additions Replaces raw pointer ownership patterns with `std::unique_ptr` and `std::map` across several core subsystems: - **Host**: `mStopWatchMap` (`QMap<int, stopWatch*>` → `std::map<int, unique_ptr<stopWatch>>`), `profileShortcuts` (`QMap<QString, QKeySequence*>` → `std::map<QString, unique_ptr<QKeySequence>>`). Removes `qDeleteAll` in destructor and `delete mMMCPServer`. - **TMap**: `mpRoomDB` raw pointer → `unique_ptr` - **VarUnit**: `base` raw pointer → `unique_ptr` - **TTrigger**: condition map storage converted to `unique_ptr`, destructor simplified - **discord**: handler and presence maps converted from raw pointer `QMap` to `unique_ptr` + `std::map` - **Updater**: `mFeed` and `mUpdateDialog` converted to `unique_ptr` #### Motivation for adding to Mudlet These patterns were identified as sources of memory leaks and potential use-after-free bugs. Using smart pointers makes ownership explicit, eliminates manual cleanup code, and ensures correct destruction even on early-exit paths. #### Other info (issues closed, discussion etc) sorry this one is still pretty big, but most of the changes are the same for each thing so reviewing them together probably makes sense. sadly there isn't much to see here other than no slow uptick of heap size :-[ Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 16:42:09 +12:00
mColorPatternList.emplace_back(std::move(pCT));
return true;
}
bool TTrigger::isFilterChain()
{
return (!mPatterns.empty()) && (hasChildren());
}
2009-01-24 02:50:22 +01:00
bool TTrigger::registerTrigger()
{
if (!mpHost) {
2009-01-24 02:50:22 +01:00
return false;
}
2010-03-18 16:07:12 +01:00
return mpHost->getTriggerUnit()->registerTrigger(this);
2009-01-24 02:50:22 +01:00
}
2010-08-25 00:41:43 +02:00
void TTrigger::compileAll()
{
mNeedsToBeCompiled = true;
if (!compileScript()) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::white, Qt::red) << "ERROR: Lua compile error. compiling script of Trigger:" << mName << "\n" >> mpHost;
}
2010-08-25 00:41:43 +02:00
mOK_code = false;
}
setRegexCodeList(mPatterns, mPatternKinds);
for (auto trigger : *mpMyChildrenList) {
trigger->compileAll();
2010-08-25 00:41:43 +02:00
}
}
2009-01-24 02:50:22 +01:00
void TTrigger::compile()
{
if (mNeedsToBeCompiled) {
if (!compileScript()) {
Improve: move away from constructor initialisation lists (part 4) (#6458) This PR is also concerned with cleaning up the `mudlet` class. As well as moving the elements in the constructor initialisation to the header file it also renames and groups by member/method visibility and then largely by name within each grouping (possibly adding "type prefixes" to some members or swapping word orders) and moves some global values from the `.cpp` file to the `.h` file - making them explicitly `static` if not `const`. Sorted by "old name" here the changes are (if a type is not specified after the `==>` then it is unchanged): * `(“global” QPointer<mudlet>) mudlet::_self` ==> `(inline static QPointer<mudlet>) mudlet::smpSelf` * `mudlet::~mudlet()` ==> `mudlet::~mudlet override` * `(Announcer*) mudlet::announcer` ==> `mudlet::mpAnnouncer` * `(QKeySequence) mudlet::closeProfileKeySequence` ==> `mudlet::mKeySequenceCloseProfile` * `(QPointer<QShortcut>) mudlet::closeProfileShortcut` ==> `mudlet::mpShortcutCloseProfile` * `(QKeySequence) mudlet::connectKeySequence` ==> `mudlet::mKeySequenceConnect` * `(QPointer<QShortcut>) mudlet::connectShortcut` ==> `mudlet::mpShortcutConnect` * `(“global” bool) mudlet::debugMode` ==> `(static bool) mudlet::smDebugMode` * `(QKeySequence) mudlet::disconnectKeySequence` ==> `mudlet::mKeySequenceDisconnect` * `(QPointer<QShortcut>) mudlet::disconnectShortcut` ==> `mudlet::mpShortcutDisconnect` * `(bool) mudlet::firstLaunch` ==> `(static bool) mudlet::smFirstLaunch` * `(QKeySequence) mudlet::inputLineKeySequence` ==> `mudlet::mKeySequenceInputLine` * `(QPointer<QShortcut>) mudlet::inputLineShortcut` ==> `mudlet::mpShortcutInputLine` * `(Hunhandle*) mudlet::mHunspell_sharedDictionary` ==> `mudlet::mpHunspell_sharedDictionary` * `(QPointer<dlgConnectionProfiles>) mudlet::mConnectionDialog` ==> `mudlet::mpConnectionDialog` * `(“global” QVariantHash) mudlet::mLuaFunctionNames` ==> `(static QVariantHash) mudlet::smLuaFunctionNames` * `(Inline static bool) mudlet::mMirrorToStdOut` ==> `mudlet::smMirrorToStdOut` * `(QString) mudlet::mMudletTranslationsPathName` ==> `mudlet::mPathNameMudletTranslations` * `(QKeySequence) mudlet::modulesKeySequence` ==> `mudlet::mKeySequenceModules` * `(QPointer<QShortcut>) mudlet::modulesShortcut` ==> `mudlet::mpShortcutModules` * `(“global” QPointer<QMainWindow>) mudlet::mpDebugArea` ==> `(static QPointer<QMainWindow>) mudlet::smpDebugArea` * `(“global” QPointer<TConsole>) mudlet::mpDebugConsole` ==> `(static QPointer<TConsole>) mudlet::smpDebugConsole` * `(QString) mudlet::mQtTranslationsPathName` ==> `mudlet::mPathNameQtTranslations` * `(QPointer<ShortcutsManager>) mudlet::mShortcutsManager` ==> `mudlet::mpShortcutsManager` * `(bool) mudlet::mshowMapAuditErrors` ==> `mudlet::mShowMapAuditErrors` * `(const int) mudlet::mTranslationGoldStar` ==> `(static const int) mudlet::scmTranslationGoldStar` * `(QKeySequence) mudlet::multiViewKeySequence` ==> `mudlet::mKeySequenceMultiView` * `(QPointer<QShortcut>) mudlet::multiViewShortcut` ==> `mudlet::mpShortcutMultiView` * `(QKeySequence) mudlet::notepadKeySequence` ==> `mudlet::mKeySequenceNotepad` * `(QPointer<QShortcut>) mudlet::notepadShortcut` ==> `mudlet::mpShortcutNotepad` * `(QKeySequence) mudlet::optionsKeySequence` ==> `mudlet::mKeySequenceOptions` * `(QPointer<QShortcut>) mudlet::optionsShortcut` ==> `mudlet::mpShortcutOptions` * `(QKeySequence) mudlet::packagesKeySequence` ==> `mudlet::mKeySequencePackages` * `(QPointer<QShortcut>) mudlet::packagesShortcut` ==> `mudlet::mpShortcutPackages` * `(QStringList) mudlet::packagesToInstallList` ==> `mudlet::mPackagesToInstallList` * `(QKeySequence) mudlet::reconnectKeySequence` ==> `mudlet::mKeySequenceReconnect` * `(QPointer<QShortcut>) mudlet::reconnectShortcut` ==> `mudlet::mpShortcutReconnect` * `(“global” const bool) mudlet::scmIsDevelopmentVersion` ==> `(inline static const bool) mudlet::scmIsDevelopmentVersion` * `(“global” const bool) mudlet::scmIsPublicTestVersion` ==> `(inline static const bool) mudlet::scmIsPublicTestVersion` * `(“global” const bool) mudlet::scmIsReleaseVersion` ==> `(inline static const bool) mudlet::scmIsReleaseVersion` * `(“global” const QString) mudlet::scmMudletXmlDefaultVersion` ==> `(inline static const QString) mudlet::scmMudletXmlDefaultVersion` * `(“global” const int) mudlet::scmQDataStreamFormat_5_12` ==> `(static const int) mudlet::scmQDataStreamFormat_5_12` * `(“global” const QVersionNumber) mudlet::scmRunTimeQtVersion` ==> `(inline static const QVersionNumber) mudlet::scmRunTimeQtVersion` * `(bool) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(void) mudlet::show_options_dialog(const QString&)` ==> `mudlet::showOptionsDialog(const QString&)` * `(QKeySequence) mudlet::showMapKeySequence` ==> `mudlet::mKeySequenceShowMap` * `(QPointer<QShortcut>) mudlet::showMapShortcut` ==> `mudlet::mpShortcutShowMap` * `(enum) mudlet::Appearance::system` ==> `mudlet::Appearance::systemSetting` This is desirable as `system` shadows a completely different `enum` value from Qt itself. * `(QKeySequence) mudlet::triggersKeySequence` ==> `mudlet::mKeySequenceTriggers` * `(QPointer<QShortcut>) mudlet::triggersShortcut` ==> `mudlet::mpShortcutTriggers` * `(Updater*) mudlet::updater` ==> `mudlet::pUpdater` * `(QString) mudlet::version` ==> `(inline static const QString) mudlet::scmVersion` Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2022-12-12 11:51:28 +00:00
if (mudlet::smDebugMode) {
Enhance: show profile indication in central debug console output (#4781) This PR adds a single character inside `[`...`]` to the beginning of (nearly) all texts displayed on the Central Debug Console which is made unique for each session of a profile run in a Mudlet application run. This marking (except for messages not from a particular profile) is not displayed when there is only one profile - and the start and end (and a change of name) of each profile is noted and a revised listing of the symbol used for each active profile is shown each time it changes. To do this the previous dummy `>> 0` used at the end of a `TDebug()` message creation has been changed to instead take a pointer to a profile's `host` instance - from which the profile name is extracted. To allow for multi-coloured messages to be concatenated, inserting a `(QChar) TDebug::csmContinue` element at the start of a new `TDebug` text will cause it to be appended onto the end of a previous `TDebug` text without acquiring the profile indication marking. Messages that are generated with a `nullptr` as the Host pointer are expected to be messages from the Mudlet Application rather than a particular profile and they will always be marked with a `[*]`. When multi-playing closing a profile and reopening it again will cause a new identifier to the used for the subsequent run - so it can be seen which run any messages are from. The current design uses identifiers from the sequence: 'A' to 'Z' - after that set of 26 marks are exhausted then all subsequent profile runs in that Mudlet application run reused the same letters as they were freed up by that profile being closed. In the pathological case of some user trying to run 27 profiles at a time then the excess will be shown with a '?'. it would be possible to extend the sequence but as the Central Debug console is intended to help with debugging it is not expected for the finite number of identifiers to be a serious limitation! This will close #804 (originally a LaunchPad issue: https://bugs.launchpad.net/mudlet/+bug/1658271 )! Also: * simplify some Lua handling of boolean returns and conditions based upon an integer value. * in `TTrigger::match(...)` use `QStringList::at(...)` in some places where it is faster/safer than `QStringList::operator[]()`. * Remove a rogue line-feed prior to a: "LUA: code compiled without errors. OK" message which was making it more spammy than it needed to be. Note that `(bool) TLuaInterpreter::compileScript(const QString&)` has been found to be unused so has been removed from the codebase. Enhanced to also add tags to tab bar as well as CDC when the latter is visible - this will help the user to track the displayed messages to the appropriate tab without having to look for the messages shown when two or more profiles are active and a new one is loaded or when three or more profiles are active and one of them is closed. Revised to use a different symbol (heavy asterix) instead of a plain one This is for non-profile specific messages and sits better on the text line and is bigger/heavier than a standard (ASCII) Asterix symbol. Revised as CodeFactor wanted the `TTabBar` constructor with a single `Host*` argument to be marked `explicit`. Signed-off-by: Stephen Lyons <slysven@virginmedia.com> Co-authored-by: Vadim Peretokin <vperetokin@gmail.com>
2021-03-27 21:38:50 +00:00
TDebug(Qt::white, Qt::red) << "ERROR: Lua compile error. compiling script of Trigger:" << mName << "\n" >> mpHost;
}
2009-04-09 21:42:11 +02:00
mOK_code = false;
2009-01-24 02:50:22 +01:00
}
}
for (auto trigger : *mpMyChildrenList) {
trigger->compile();
2009-01-24 02:50:22 +01:00
}
}
bool TTrigger::setScript(const QString& script)
2009-01-24 02:50:22 +01:00
{
fix: replacing a temp item's script no longer keeps running the old function callback (#9496) #### Brief overview of PR changes/additions - `setScript()` on a temp trigger/timer/alias/key that was created with a function callback (`tempTrigger`/`tempTimer`/`tempAlias`/`tempKey` with a function argument) now releases that callback: it clears the registered-function flag and removes the function from the Lua registry before switching to the new script string. - Without this, such an item would keep executing the stale callback so the new script never runs (triggers/aliases/keys), and the old function would never be freed from the Lua registry (all four types). - Adds a functional test (`SetScriptCallbackTest`) covering all four types, plus the empty-script and non-callback (no-op) cases. #### Motivation for adding to Mudlet Keeps a temp item's execution state and cleanup consistent when its script is replaced. No current scripting API or editor path replaces a temp item's script, so this closes the gap before anything can reach it. #### Other info (issues closed, discussion etc) A temp item's function callback is stored in the Lua registry keyed by the item pointer; `setScript()` previously left both that entry and the `mRegisteredAnonymousLuaFunction` flag untouched. Because each destructor picks its cleanup branch from `mScript.isEmpty()`, once a non-empty script was set the pointer-keyed entry was orphaned. `TAction` (buttons) has no function-callback path and is unaffected. Behaviour of every existing caller is unchanged, covered by the no-op guard case. **Test case:** ``` run: flock /tmp/mudlet-functional-tests.lock ctest --output-on-failure -R SetScriptCallbackTest ``` All 6 sub-tests pass with the fix; 5 of 6 fail against the pre-fix baseline (the non-callback no-op case passes by design, guarding that existing behaviour is unchanged). Related suites `EnableDisableByNameTest` and `TFeedTriggersRecursionTest` still pass. Assisted-by: Claude:claude-opus-4-8
2026-07-30 08:35:03 +02:00
// Switching from a registered anonymous Lua function (set up by tempTrigger with a
// function argument) to a script string: release the old function from the Lua
// registry and leave callback mode. Otherwise execute() keeps calling the stale
// function so the new script never runs, and the registry entry leaks - the
// destructor would take its mScript-based branch and delete the compiled function.
if (mRegisteredAnonymousLuaFunction) {
if (mpHost) {
mpHost->mLuaInterpreter.delete_luafunction(this);
}
mRegisteredAnonymousLuaFunction = false;
}
2009-04-09 21:42:11 +02:00
mScript = script;
if (script.isEmpty()) {
mNeedsToBeCompiled = false;
mOK_code = true;
} else {
mNeedsToBeCompiled = true;
mOK_code = compileScript();
}
2009-04-09 21:42:11 +02:00
return mOK_code;
}
bool TTrigger::compileScript()
{
mFuncName = qsl("Trigger%1").arg(QString::number(mID));
const QString code = qsl("function %1() %2\nend").arg(mFuncName, mScript);
2009-04-09 21:42:11 +02:00
QString error;
if (mpLua->compile(code, error, qsl("Trigger: %1").arg(getName()))) {
2009-04-09 21:42:11 +02:00
mNeedsToBeCompiled = false;
mOK_code = true;
return true;
}
mOK_code = false;
setError(error);
return false;
2009-04-09 21:42:11 +02:00
}
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
namespace {
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
// Tracks the innermost trigger running its script, so feedTriggers() can name the
// culprit when aborting an endless loop, and the same-line creation lineage of
// that trigger's root, so anything the script creates joins it; RAII restores the
// prior values on exit.
class ExecutingTriggerGuard
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
{
public:
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
ExecutingTriggerGuard(TriggerUnit* pUnit, const QString* pName, const int chainId, const int generation)
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
: mpUnit(pUnit)
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
, mpPreviousName(pUnit->currentExecutingTriggerName())
, mPreviousChainId(pUnit->currentSameLineChainId())
, mPreviousGeneration(pUnit->currentSameLineGeneration())
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
{
mpUnit->setCurrentExecutingTriggerName(pName);
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
mpUnit->setCurrentSameLineChain(chainId, generation);
}
~ExecutingTriggerGuard()
{
mpUnit->setCurrentExecutingTriggerName(mpPreviousName);
mpUnit->setCurrentSameLineChain(mPreviousChainId, mPreviousGeneration);
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
}
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
ExecutingTriggerGuard(const ExecutingTriggerGuard&) = delete;
ExecutingTriggerGuard& operator=(const ExecutingTriggerGuard&) = delete;
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
private:
TriggerUnit* mpUnit;
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
const QString* mpPreviousName;
int mPreviousChainId;
int mPreviousGeneration;
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
};
} // namespace
2009-04-09 21:42:11 +02:00
void TTrigger::execute()
{
Fix triggers being deleted when a script creates a lot of them at once (#9724) #### Brief overview of PR changes/additions - One budget of 100 covered every root trigger created while a line was processed, and tripping it deactivated all of them, so a script arming 101 unrelated triggers lost all 101. - Triggers created mid-line now carry the creation lineage they belong to and how many generations deep they sit in it. A batch is one generation however big it is; only a trigger that re-creates itself keeps adding generations, so that is the only shape the budget counts. The limit is 1000 generations, and only the runaway lineage is stopped and named. - Generations do not bound a lineage that widens as it deepens, so past 20000 creations on one line new triggers stop being offered that line. Nothing is disowned there - they are all still armed for the lines that follow. #### Motivation for adding to Mudlet #9697 fixed a real freeze, but its counter had no lineage, so it destroyed legitimate triggers along with the runaway. Any routine arming more than 100 triggers from a trigger loses them, permanent ones included, which is a regression against 4.22.0. #### Other info (issues closed, discussion etc) Fixes a regression introduced by merged #9697; release-blocking for 5.0. Test case: `lua fired=0; tempTrigger("GATE", function() for i=1,200 do tempTrigger("PAY", function() fired=fired+1 end) end end); feedTriggers("\nGATE\n"); feedTriggers("\nPAY\n"); print(fired)` - prints 0 before, 200 after. A/B against a shipped 4.22.0 binary (4.22.0 / 5.0 RC / this PR), counted on the line after the one that armed them: 1001 unrelated temp triggers 1001 / 0 / 1001; two scripts of 600 each 600+600 / 0+0 / 600+600; 1001 permanent triggers 1001 / 0 / 1001. #9697's freeze is still stopped and bounded (601 runaway lines in 8 s, RSS flat at ~820 MB) and its own tests still pass. Eleven new tests parameterise the creation count, and cover nested passes and folder/filter-chain children, which none of #9697's did - that is why this shipped. Assisted-by: Claude:claude-opus-5
2026-08-08 08:26:28 +02:00
// Only root triggers carry a lineage, so a trigger nested in a folder or a
// filter chain reads the one on the root its subtree hangs from. Creations
// that go under a parent rather than to the root list are outside this
// accounting altogether, as they are outside the list processDataStream()
// walks.
const TTrigger* pRoot = this;
while (pRoot->getParent()) {
pRoot = pRoot->getParent();
}
const ExecutingTriggerGuard executingTriggerGuard(mpHost->getTriggerUnit(), &mName, pRoot->sameLineChainId(), pRoot->sameLineGeneration());
fix: prevent crash from a trigger that endlessly feeds itself (#9368) #### Brief overview of PR changes/additions Abort with a Lua error (naming the trigger) when trigger processing recurses past a depth limit, instead of overflowing the stack. Covers both `feedTriggers()` and `feedTelnet()` loops, each with a limit sized to its stack usage. #### Motivation for adding to Mudlet A trigger whose action calls `feedTriggers()` with text that re-matches it recurses the C++ stack until Mudlet hard-crashes (Sentry `fbda193d`, `EXCEPTION_STACK_OVERFLOW`); this turns that into a clear, recoverable script error. Review found `feedTelnet()` crashes the same way, so it gets the same treatment. #### Other info (issues closed, discussion etc) Crash seen on Windows in Sentry. The same loop on Linux/macOS only reaches Lua's own `C stack overflow` guard (~200 nested C calls) - cryptic, but no crash; Windows' smaller ~1 MB stack dies first. The fix's depth limit (50) trips before either, so every platform gets the same clear, named error. `feedTelnet()` needs a much lower limit (5): each nested telnet processing level holds ~100KB of stack buffers, so a 1MB stack dies after ~8 levels. Fixing this also surfaced a reentrancy bug where nested `feedTelnet()` re-posted the ancestors' pending `mMudData`, duplicating output lines and abort errors; `postData()` now detaches the data before posting. **Test case:** 1. New regex trigger: pattern `^loopme$`, script `feedTriggers("loopme\n")`. 2. Run `feedTriggers("loopme\n")`. 3. Before: crash (Windows) / `<C stack overflow>` (Linux). After: it stops with an error naming the trigger and stays running. 4. Same with `feedTelnet("loopme\n")` in the trigger and prompt (on a disconnected profile): stops with a single error instead of crashing. --------- Signed-off-by: Vadim Peretokin <vperetokin@hey.com>
2026-07-13 20:14:21 +02:00
if (mSoundTrigger) { /* eventually something should be added to the gui to change sound volumes. 100=full volume */
QString mediaFileName = mSoundFile;
if (QDir::homePath().contains('\\')) {
mediaFileName.replace('/', R"(\)");
} else {
mediaFileName.replace('\\', "/");
}
TMediaData mediaData{};
mediaData.setMediaProtocol(TMediaData::MediaProtocolAPI);
mediaData.setMediaType(TMediaData::MediaTypeSound);
mediaData.setMediaFileName(mediaFileName);
mediaData.setMediaVolume(TMediaData::MediaVolumeMax);
mpHost->mpMedia->playMedia(mediaData);
}
if (!mCommand.isEmpty()) {
mpHost->send(mCommand);
}
if (mNeedsToBeCompiled) {
if (!compileScript()) {
return;
2009-04-09 21:42:11 +02:00
}
}
if (mRegisteredAnonymousLuaFunction) {
2018-07-11 20:39:50 +02:00
if (Q_LIKELY(mExpiryCount <= 0)) {
mpLua->call_luafunction(this);
} else {
// if the trigger is a temporary expiring one,
// don't expire if it returned true
auto result = mpLua->callLuaFunctionReturnBool(this);
// if the function ran okay and returned true, it wants to extend the expiry count
if (result.first && result.second) {
mExpiryCount++;
}
}
return;
}
if (mScript.isEmpty()) {
return;
}
if (mIsMultiline) {
2018-07-11 20:39:50 +02:00
if (Q_LIKELY(mExpiryCount <= 0)) {
mpLua->callMulti(mFuncName, mName);
} else {
// if the trigger is a temporary expiring one,
// don't expire if it returned true
auto result = mpLua->callMultiReturnBool(mFuncName, mName);
if (result.second) {
mExpiryCount++;
}
}
} else {
2018-07-11 20:39:50 +02:00
if (Q_LIKELY(mExpiryCount <= 0)) {
mpLua->call(mFuncName, mName);
} else {
// if the trigger is a temporary expiring one,
// don't expire if it returned true
auto result = mpLua->callReturnBool(mFuncName, mName);
if (result.second) {
mExpiryCount++;
}
}
2009-01-24 02:50:22 +01:00
}
}
void TTrigger::enableTrigger(const QString& name)
2009-01-24 02:50:22 +01:00
{
if (mName == name) {
setIsActive(true);
2009-01-24 02:50:22 +01:00
}
for (auto trigger : *mpMyChildrenList) {
trigger->enableTrigger(name);
2009-01-24 02:50:22 +01:00
}
}
void TTrigger::disableTrigger(const QString& name)
2009-01-24 02:50:22 +01:00
{
if (mName == name) {
setIsActive(false);
2009-01-24 02:50:22 +01:00
}
for (auto trigger : *mpMyChildrenList) {
trigger->disableTrigger(name);
2009-01-24 02:50:22 +01:00
}
}
TTrigger* TTrigger::killTrigger(const QString& name)
2009-01-24 02:50:22 +01:00
{
if (mName == name) {
setIsActive(false);
2009-01-24 02:50:22 +01:00
}
for (auto trigger : *mpMyChildrenList) {
trigger->killTrigger(name);
2009-01-24 02:50:22 +01:00
}
return nullptr;
2009-01-24 02:50:22 +01:00
}
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// Provide a pair of helpers which means we can provide a slightly more readable
// pattern text for the odd cases - and do it in one place:
QString TTrigger::createColorPatternText(const int fgColorCode, const int bgColorCode)
{
QString fgText;
QString bgText;
if (fgColorCode == scmIgnored) {
fgText = QLatin1String("IGNORE");
} else if (fgColorCode == scmDefault) {
fgText = QLatin1String("DEFAULT");
} else {
fgText = qsl("%1").arg(fgColorCode, 3, 10, QLatin1Char('0'));
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
}
if (bgColorCode == scmIgnored) {
bgText = QLatin1String("IGNORE");
} else if (bgColorCode == scmDefault) {
bgText = QLatin1String("DEFAULT");
} else {
bgText = qsl("%1").arg(bgColorCode, 3, 10, QLatin1Char('0'));
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
}
Infrastructure: remove unneeded control from trigger editor (#7505) #### Brief overview of PR changes/additions Simplify and improve the "trigger" editor part of the "Editor" by combining/removing some group boxes and making a third one not have a check-box. Also move them all from the bottom of the left to the right side of that area and improve the behaviour as the splitter for the right side is adjusted. #### Motivation for adding to Mudlet Improving the UI - helping to make the controls a bit more intuitive. #### Other info (issues closed, discussion etc) Having a QSpinBox to control the "condition line" delta for AND/Multi-line triggers as well as placing it in a checkable group-box to enable it is more complex than it needs to be. This PR removes the checkbox and instead uses the ability of a `QComboBox` to have a "special value" which it presents different - in this case to report the trigger as an OR/Multi-item type trigger. Having done this I realised that it and the other two items at the bottom of the left side of the "triggers" editor could be simplified further and all moved to the right side. Then I had to tweak the code that showed/hid the right and bottom widgets (since the bottom ones had gone). Finally I put in code to disable the "OR multi-item"/"AND multi-line" control when there is less than two "items" in the trigger. Also: * rename `(QWidget*) dlgTriggerEditor::HpatternList` ==> `dlgTriggerEditor::mpWidget_triggerItems` * convert the - not used as a button - `pushButton_prompt` from a `QPushButton` to a `QLabel` - and make it be enabled when GA/EoRs are detected - as well as changing the text as before. This was prompted by working on the fix for #7480.
2024-11-04 06:55:05 +00:00
// QString::compare(...) returns zero (boolean false) on a match, or a
// non-zero (boolean true) on no match - and we want to detect when BOTH
// texts are IGNORE so we return an empty string in that case only - so that
// it is equivalent to an empty other trigger type:
return (fgText.compare(QLatin1String("IGNORE")) || bgText.compare(QLatin1String("IGNORE"))) ? qsl("ANSI_COLORS_F{%1}_B{%2}").arg(fgText, bgText) : QString();
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
}
void TTrigger::decodeColorPatternText(const QString& patternText, int& fgColorCode, int& bgColorCode)
{
// The numbers used for the text have changed - see table in:
// TColorTable* TTrigger::createColorPattern(int ansiFg, int ansiBg)
const QRegularExpression regex = QRegularExpression(qsl("^ANSI_COLORS_F{(\\d+|DEFAULT|IGNORE)}_B{(\\d+|DEFAULT|IGNORE)}$"));
// Was QRegularExpression regex = QRegularExpression(qsl(R"(FG(\d+)BG(\d+))"));
const QRegularExpressionMatch match = regex.match(patternText);
Refactor: clean up TBuffer text format aspects (#1840) This is the edited summary of a squash and merge of 14 commits: Adds support for SGR Reverse (swap foreground and background colours) "7"/"27" for On/Off and SGR Overline "53"/"55" for On/Off Remove unused cruft: * (void) TTextEdit::drawFrame(QPainter&, const QRect&) * (void) TTextEdit::updateLastLine * const QChar cLF & cSPACE in TBuffer (as it happens they are completely unused and redundant as the enum QChar::SpecialCharacter provides QChar::LineFeed and QChar::Space to provide the same constants) * (QTime) TBuffer::mTime * (void) TConsole::echoUserWindow(const QString&) * (QPoint) TBuffer::insert(QPoint&, const QString&, int, int, int, int, int, int, bool, bool, bool, bool) * (void) TConsole::printDebug(...) functionally the same as one type of (void) TConsole::print(...) just with a different order of arguments. Convert #define constants TCHAR_BOLD etc. into a QFLag/enum TChar::AttributeFlags which is declared and capable of QFlag OR operations. Refactor a number of methods that take lots of bools and ints as individual formatting options and colour components to take single TChar::AttributeFlags and one or two QColors instead. Remove a large number of (int) colour value component values as member variables in TBuffer as they are not needed. Convert highly repetitive intermediate methods to setBold, setItalics etc. to take a (combinations allowed) TChar::Attribute flag value instead. Convert 2x3 int as colour components (r,g,b) in TColorTable defined in TTrigger class to a pair of QColors. Remove unused QString argument from: * (void) mudlet::setLink(...) * (void) TConsole::setLink(...) Remove unused QColor argument from: * (inline void) TTextEdit::drawCharacters(...) Refactor arguments in: *(QString) TBuffer::bufferToHtml(QPoint P1, QPoint P2, bool allowedTimestamps, int spacePadding = 0) to: (QString) TBuffer::bufferToHtml(const bool showTimeStamp = false, const int row = -1, const int endColumn = -1, const int startColumn = 0, int spacePadding = 0) Convert to const references some method arguments. Add TBuffer::set[BF]gColor(...) overloads that take a QColor argument. Add selection state methods select()/deselect()/isSelected() const methods to TChar class to hide/separate the selection process from the formatting effect. (TChar::Reverse tracks the ANSI SGR reverse colour attribute and its effect is EX-ORed with the (bool) TChar::mIsSelected flag). Add a new tempAnsiColorTrigger lua function that, unlike tempColorTrigger uses the correct ANSIcolors in the range 0-15 - although the original also handles the 256 colour range in the 16-255 correctly those first 16 values are miss-mapped and it is not possible to change them without breakage. Adds 256-color support to Editor GUI for color triggers - and allows choosing the default (unmodified) fore or background colors to match one (the previous did not) and also allows one of the fore or background color to be ignored so only the other is considered. The ignored color case is saved in the profile data and can exported but MAY not work in previous Mudlet versions which cannot handle the value used! It is also reported as an error to have a color trigger with both fore and background ignored in both the lua functions and in the GUI. Also: Fixed a code structure issue in TLuaInterpreter::debug() which would not work correctly if there was more than one value on the lua stack to print out. This will close issues #477 and #703. Converted some `QObject::connect` calls to the new Qt5 compile time version. Removed an unused `TTrigger*` argument from `dlgColorTrigger::setupBasicButtons(...)`. Removed an unused flag: * `(bool) TConsole::mSaveLayoutRequested Also spotted some dead code from abandoned attempt to support blinking, some reordering that a new version of Qt spotted as needed in the TBuffer and TChar constructor initialisation lists, and a operator precedence item that could be clarified with an addition pair of `(`...`)`s. A previous error in the prior PR that this one is attempting to replace had a problem in HTML generation that I reproduced here and which needed the same fix (a missing escaped `"` mark). An upgraded Qt Creator pointed out to me some initiliser list issues in `TBuffer` and `TConsole`; and some C-style casts in some font settings in the latter class. Remove a debugging output line that is not useful now and will be spammy. Modernise a triplet of QObject::connect(...) calls that will otherwise clash harder when merged into development after "upgrade-to-qt5-connect" PR has also been merged into the main branch. Also: * add some explanation/help text to the dlgColorTrigger dialog. * revise the text explaining the formula (232 + grey scale value 0..23) used for colours from the 24 grey-scale part of the 256 colour range. * add some tool-tips to parts of the dlgColorTrigger dialog. * add a generic static method to the mudlet class to provide a consistent and re-usable "HTML" wrapper around text - which will be particularly useful for tool-tip generation. Revise: change colour trigger UI to hide colours 16-255 by default This follows a suggestion from a peer in the review process. Update: add Wiki documentation link comment Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2019-01-28 23:23:53 +00:00
// scmDefault is the new code for "default" colour (as 0 is a valid ANSI color number!)
// scmIgnored is the new code for "reset" i.e. NOT set color trigger (i.e. don't
// bother with checking this part of the colour)
if (match.capturedStart() > -1) {
// There *is* a match - now examine what was found:
if (match.captured(1) == QLatin1String("DEFAULT")) {
fgColorCode = scmDefault;
} else if (match.captured(1) == QLatin1String("IGNORE")) {
fgColorCode = scmIgnored;
} else {
fgColorCode = match.captured(1).toInt();
}
if (match.captured(2) == QLatin1String("DEFAULT")) {
bgColorCode = scmDefault;
} else if (match.captured(2) == QLatin1String("IGNORE")) {
bgColorCode = scmIgnored;
} else {
bgColorCode = match.captured(2).toInt();
}
} else {
fgColorCode = scmIgnored;
bgColorCode = scmIgnored;
}
}
QString TTrigger::packageName(TTrigger* pTrigger)
{
if (!pTrigger) {
return QString();
}
if (!pTrigger->mPackageName.isEmpty()) {
return !mpHost->mInstalledModules.contains(pTrigger->mPackageName) ? pTrigger->mPackageName : QString();
}
if (pTrigger->getParent()) {
return packageName(pTrigger->getParent());
}
return QString();
}
QString TTrigger::moduleName(TTrigger* pTrigger)
{
if (!pTrigger) {
return QString();
}
if (!pTrigger->mPackageName.isEmpty()) {
return mpHost->mInstalledModules.contains(pTrigger->mPackageName) ? pTrigger->mPackageName : QString();
}
if (pTrigger->getParent()) {
return moduleName(pTrigger->getParent());
}
return QString();
}