2020-01-12 21:13:58 +00:00
/***************************************************************************
2014-08-15 02:11:43 -07:00
* Copyright ( C ) 2008 - 2013 by Heiko Koehn - KoehnHeiko @ googlemail . com *
* Copyright ( C ) 2014 by Ahmed Charles - acharles @ outlook . com *
2017-04-19 09:36:15 -04:00
* Copyright ( C ) 2016 by Chris Leacy - cleacy1972 @ gmail . com *
2026-04-29 12:34:30 +01:00
* Copyright ( C ) 2017 - 2018 , 2021 , 2026 by Stephen Lyons *
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 . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-08-15 02:11:43 -07:00
2009-01-24 02:50:22 +01:00
# include "TTrigger.h"
2014-08-15 02:11:43 -07:00
2009-01-24 02:50:22 +01:00
# include "Host.h"
2014-08-15 02:11:43 -07:00
# include "TConsole.h"
2009-01-24 02:50:22 +01:00
# include "TDebug.h"
2014-08-15 02:11:43 -07:00
# include "TMatchState.h"
2022-02-20 01:06:50 -05:00
# include "TMedia.h"
2017-04-14 00:40:02 -07:00
# include "mudlet.h"
2022-02-20 01:06:50 -05:00
# include <QRegularExpression>
2014-08-15 02:11:43 -07:00
2018-08-30 13:48:42 +02:00
# include <cassert>
2009-04-02 00:20:23 +02:00
# include <sstream>
2014-08-15 02:11:43 -07: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
// 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 ;
2009-05-09 14:36:12 +02:00
2017-06-29 07:08:22 +02:00
TTrigger : : TTrigger ( TTrigger * parent , Host * pHost )
: Tree < TTrigger > ( parent )
2021-11-07 22:17:10 +01:00
, mpHost ( pHost )
2017-06-26 16:46:54 +02:00
, 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
2025-01-01 10:18:02 +01:00
TTrigger : : TTrigger ( const QString & name , const QStringList & patterns , const QList < int > & patternKinds , bool isMultiline , Host * pHost )
2017-08-03 08:46:00 +02:00
: Tree < TTrigger > ( nullptr )
2021-11-07 22:17:10 +01:00
, mpHost ( pHost )
, mName ( name )
2022-01-15 11:34:56 +01:00
, mPatterns ( patterns )
, mPatternKinds ( patternKinds )
2025-01-01 10:18:02 +01:00
, mIsMultiline ( isMultiline )
2017-06-26 16:46:54 +02:00
, mpLua ( mpHost - > getLuaInterpreter ( ) )
2009-01-24 02:50:22 +01:00
{
2022-01-15 11:34:56 +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 ( ) ;
2021-01-25 02:46:21 +01:00
2017-06-26 16:46:54 +02:00
if ( ! mpHost ) {
2010-01-22 01:45:34 +01:00
return ;
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
mpHost - > getTriggerUnit ( ) - > unregisterTrigger ( this ) ;
2021-01-17 09:19:47 +01:00
if ( isTemporary ( ) ) {
if ( mScript . isEmpty ( ) ) {
mpHost - > mLuaInterpreter . delete_luafunction ( this ) ;
} else {
mpHost - > mLuaInterpreter . delete_luafunction ( mFuncName ) ;
}
}
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
void TTrigger : : setName ( const QString & name )
2009-08-18 17:48:02 +02:00
{
2020-04-03 01:45:52 +01:00
if ( ! isTemporary ( ) ) {
2019-08-08 06:09:38 +02:00
mpHost - > getTriggerUnit ( ) - > mLookupTable . remove ( mName , this ) ;
2009-11-14 02:46:52 +01:00
}
2009-08-18 17:48:02 +02:00
mName = name ;
2020-12-03 01:34:30 +00:00
mpHost - > getTriggerUnit ( ) - > mLookupTable . insert ( name , this ) ;
2009-08-18 17:48:02 +02:00
}
2025-11-29 07:21:06 +01:00
static void pcre2_code_deleter ( pcre2_code * pointer )
2014-09-20 01:05:03 -07:00
{
2025-11-29 07:21:06 +01:00
pcre2_code_free ( pointer ) ;
2014-09-20 01:05:03 -07: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
static void pcre2_match_data_deleter ( pcre2_match_data * pointer )
{
pcre2_match_data_free ( pointer ) ;
}
2020-11-05 10:56:26 +01:00
//FIXME: lock if code *OR* regex doesn't compile
2024-12-12 15:21:21 +01:00
bool TTrigger : : setRegexCodeList ( QStringList patterns , QList < int > patternKinds , bool existingTrigger )
2009-01-24 02:50:22 +01:00
{
2022-01-15 11:34:56 +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 ( ) ;
2022-01-15 11:34:56 +01:00
mPatternKinds . clear ( ) ;
2009-04-02 00:20:23 +02:00
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 ;
2009-04-13 16:00:08 +02:00
2022-01-15 11:34:56 +01:00
if ( patternKinds . size ( ) ! = patterns . size ( ) ) {
2020-11-05 10:56:26 +01:00
//FIXME: ronny managed to trigger this somehow
2022-01-15 11:34:56 +01:00
qDebug ( ) < < " [CRITICAL ERROR (plz report):] Trigger name= " < < mName < < " aborting reason: patternKinds.size() != patterns.size() " ;
2009-06-07 19:24:56 +02:00
}
2009-04-13 16:00:08 +02:00
2024-12-12 15:21:21 +01:00
if ( existingTrigger & & ( patternKinds . empty ( ) ) & & ( ! isFolder ( ) ) & & ( ! mColorTrigger ) ) {
setError ( tr ( " error: this trigger has no patterns defined " ) ) ;
2009-04-13 16:00:08 +02:00
mOK_init = false ;
2009-04-09 21:42:11 +02:00
return false ;
2009-01-24 02:50:22 +01:00
}
2009-04-13 16:00:08 +02:00
2009-04-09 21:42:11 +02:00
bool state = true ;
2009-04-13 16:00:08 +02:00
2024-12-12 15:21:21 +01:00
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
2024-12-12 15:21:21 +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 ( ) ;
2025-11-29 07:21:06 +01:00
int errorcode ;
PCRE2_SIZE erroffset ;
2024-12-12 15:21:21 +01:00
2025-11-29 07:21:06 +01:00
// 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 ) ;
2024-12-12 15:21:21 +01:00
if ( ! re ) {
2025-11-29 07:21:06 +01:00
PCRE2_UCHAR errorBuffer [ 256 ] ;
pcre2_get_error_message ( errorcode , errorBuffer , sizeof ( errorBuffer ) ) ;
const char * error = reinterpret_cast < const char * > ( errorBuffer ) ;
2024-12-12 15:21:21 +01:00
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 ;
}
2026-08-03 13:39:57 +02:00
setError ( qsl ( " <b>%1</b> " )
2024-12-12 15:21:21 +01:00
. 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 {
2026-01-08 08:37:51 +01:00
pcre2_jit_compile ( re . data ( ) , PCRE2_JIT_COMPLETE ) ;
2024-12-12 15:21:21 +01:00
if ( mudlet : : smDebugMode ) {
TDebug ( Qt : : white , Qt : : darkGreen ) < < " [OK]: REGEX_COMPILE OK \n " > > mpHost ;
}
2009-08-18 17:48:02 +02:00
}
2024-12-12 15:21:21 +01:00
mRegexMap [ i ] = re ;
mTriggerContainsPerlRegex = true ;
2009-04-09 21:42:11 +02:00
}
2017-03-13 02:01:07 +00:00
2024-12-12 15:21:21 +01: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 \n end " ) . arg ( funcName . c_str ( ) , patterns [ i ] ) ;
QString error ;
if ( ! mpLua - > compile ( code , error , QString : : fromStdString ( funcName ) ) ) {
2026-08-03 13:39:57 +02:00
setError ( qsl ( " <b>%1</b> " )
2024-12-12 15:21:21 +01:00
. 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 ;
2017-06-26 16:46:54 +02:00
}
}
2017-03-13 02:01:07 +00:00
2024-12-12 15:21:21 +01: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 ) {
2026-08-03 13:39:57 +02:00
setError ( qsl ( " <b>%1</b> " )
2024-12-12 15:21:21 +01:00
. 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 ;
}
2017-10-05 22:09:32 +03:00
2024-12-12 15:21:21 +01:00
// 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 ) ;
2024-12-12 15:21:21 +01:00
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 ) ;
2009-11-04 00:33:42 +01:00
}
2009-04-13 16:00:08 +02:00
}
2009-04-02 00:20:23 +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
mOK_init = state ;
2009-04-09 21:42:11 +02:00
return state ;
2009-01-24 02:50:22 +01:00
}
2026-07-27 20:20:48 +02:00
bool TTrigger : : match_perl ( char * haystackC , const QString & haystack , int patternNumber , int posOffset , int lineNumber )
2009-01-24 02:50:22 +01:00
{
2022-01-06 21:35:10 +01:00
assert ( mRegexMap . contains ( patternNumber ) ) ;
2010-03-18 16:07:12 +01:00
2025-11-29 07:21:06 +01:00
QSharedPointer < pcre2_code > const re = mRegexMap [ patternNumber ] ;
2009-03-20 19:43:29 +01:00
2017-06-26 16:46:54 +02:00
if ( ! re ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
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 ;
2017-06-26 16:46:54 +02:00
}
2009-03-20 19:43:29 +01:00
return false ; //regex compile error
}
2010-03-18 16:07:12 +01:00
2023-05-14 15:06:15 +02: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 ;
}
2025-11-29 07:21:06 +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
pcre2_match_data * match_data = matchData . data ( ) ;
2025-11-29 07:21:06 +01:00
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
2017-06-26 16:46:54 +02:00
if ( rc < 0 ) {
2014-09-21 15:22:58 -07:00
return false ;
2022-01-06 21:35:10 +01:00
}
2026-07-27 20:20:48 +02:00
processRegexMatch ( haystackC , haystack , patternNumber , posOffset , re , haystackCLength , match_data , rc , lineNumber ) ;
2022-01-06 21:35:10 +01:00
return true ;
}
2026-07-27 20:20:48 +02:00
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 )
2022-01-06 21:35:10 +01:00
{
2025-11-29 07:21:06 +01:00
PCRE2_SIZE * ovector = pcre2_get_ovector_pointer ( match_data ) ;
2010-03-18 16:07:12 +01:00
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : blue , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) matched. \n " > > mpHost ;
2022-01-06 21:35:10 +01:00
}
int i = 0 ;
int numberOfCaptureGroups = 0 ;
std : : list < std : : string > captureList ;
std : : list < int > posList ;
QMap < QString , QPair < int , int > > namePositions ;
NameGroupMatches nameGroups ;
2017-06-26 16:46:54 +02:00
for ( i = 0 ; i < rc ; i + + ) {
2022-01-06 21:35:10 +01:00
const char * substring_start = haystackC + ovector [ 2 * i ] ;
2023-05-14 15:06:15 +02:00
const int substring_length = ovector [ 2 * i + 1 ] - ovector [ 2 * i ] ;
2009-02-16 17:22:00 +01:00
std : : string match ;
2017-06-26 16:46:54 +02:00
if ( substring_length < 1 ) {
captureList . push_back ( match ) ;
posList . push_back ( - 1 ) ;
2009-09-30 22:13:12 +02:00
continue ;
}
2026-04-10 20:42:45 +02:00
const int utf16_pos = QString : : fromUtf8 ( haystackC , ovector [ 2 * i ] ) . length ( ) ;
2017-06-26 16:46:54 +02:00
match . append ( substring_start , substring_length ) ;
captureList . push_back ( match ) ;
2019-10-11 06:42:13 +00:00
posList . push_back ( utf16_pos + posOffset ) ;
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
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 ;
2017-06-26 16:46:54 +02:00
}
2009-02-16 05:06:37 +01:00
}
2021-07-31 11:17:27 +02:00
2025-11-29 07:21:06 +01:00
uint32_t namecount = 0 ;
uint32_t name_entry_size = 0 ;
PCRE2_SPTR tabptr = nullptr ;
2021-07-31 11:17:27 +02:00
2025-11-29 07:21:06 +01:00
pcre2_pattern_info ( re . data ( ) , PCRE2_INFO_NAMECOUNT , & namecount ) ;
2010-03-18 16:07:12 +01:00
2021-02-07 17:21:04 +01:00
if ( namecount > 0 ) {
2025-11-29 07:21:06 +01:00
// 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 ) {
2023-05-14 15:06:15 +02:00
const int n = ( tabptr [ 0 ] < < 8 ) | tabptr [ 1 ] ;
2025-11-29 07:21:06 +01:00
auto name =
QString : : fromUtf8 ( reinterpret_cast < const char * > ( & tabptr [ 2 ] ) ) . trimmed ( ) ; //NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-bounds-constant-array-index)
2026-04-10 20:42:45 +02:00
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)
2021-07-31 11:17:27 +02:00
auto capture = QString : : fromUtf8 ( substring_start , substring_length ) ;
2021-02-07 17:21:04 +01:00
nameGroups < < qMakePair ( name , capture ) ;
2026-04-10 20:42:45 +02:00
namePositions . insert ( name , qMakePair ( utf16_pos + posOffset , static_cast < int > ( capture . length ( ) ) ) ) ;
2009-02-16 05:06:37 +01:00
}
2010-03-18 16:07:12 +01:00
}
2017-06-26 16:46:54 +02:00
if ( mIsColorizerTrigger | | mFilterTrigger ) {
2009-04-18 20:41:19 +02:00
numberOfCaptureGroups = captureList . size ( ) ;
}
2017-06-26 16:46:54 +02:00
for ( ; mPerlSlashGOption ; ) {
2025-11-29 07:21:06 +01:00
uint32_t options = 0 ;
const PCRE2_SIZE start_offset = ovector [ 1 ] ;
2010-03-18 16:07:12 +01:00
2017-06-26 16:46:54 +02:00
if ( ovector [ 0 ] = = ovector [ 1 ] ) {
2025-11-29 07:21:06 +01:00
if ( ovector [ 0 ] > = static_cast < PCRE2_SIZE > ( haystackCLength ) ) {
2009-02-16 05:06:37 +01:00
goto END ;
2009-01-24 02:50:22 +01:00
}
2025-11-29 07:21:06 +01:00
options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED ;
2009-01-24 02:50:22 +01:00
}
2010-03-18 16:07:12 +01:00
2025-11-29 07:21:06 +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
2025-11-29 07:21:06 +01:00
if ( rc = = PCRE2_ERROR_NOMATCH ) {
2017-06-26 16:46:54 +02:00
if ( options = = 0 ) {
break ;
}
2009-02-16 05:06:37 +01:00
ovector [ 1 ] = start_offset + 1 ;
2010-03-18 16:07:12 +01:00
continue ;
2026-07-18 18:39:57 +02:00
} else if ( rc < 0 ) { // NOLINT(readability-else-after-return)
2009-02-16 05:06:37 +01:00
goto END ;
}
2018-02-28 01:03:48 +00:00
2017-06-26 16:46:54 +02:00
for ( i = 0 ; i < rc ; i + + ) {
2022-01-06 21:35:10 +01:00
const char * substring_start = haystackC + ovector [ 2 * i ] ;
2023-05-14 15:06:15 +02:00
const int substring_length = ovector [ 2 * i + 1 ] - ovector [ 2 * i ] ;
2009-09-30 22:13:12 +02:00
2009-02-16 17:22:00 +01:00
std : : string match ;
2017-06-26 16:46:54 +02:00
if ( substring_length < 1 ) {
captureList . push_back ( match ) ;
posList . push_back ( - 1 ) ;
2009-09-30 22:13:12 +02:00
continue ;
}
2026-04-10 20:42:45 +02:00
const int utf16_pos = QString : : fromUtf8 ( haystackC , ovector [ 2 * i ] ) . length ( ) ;
2017-06-26 16:46:54 +02:00
match . append ( substring_start , substring_length ) ;
captureList . push_back ( match ) ;
2019-10-11 06:42:13 +00:00
posList . push_back ( utf16_pos + posOffset ) ;
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
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 ;
2009-08-18 17:48:02 +02:00
}
2009-02-16 05:06:37 +01:00
}
2010-03-18 16:07:12 +01:00
}
2009-02-16 05:06:37 +01:00
2022-01-06 21:35:10 +01:00
END : {
if ( mIsColorizerTrigger ) {
2023-05-14 15:06:15 +02:00
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 ( ) ;
2022-01-06 21:35:10 +01:00
TConsole * pC = mpHost - > mpConsole ;
if ( Q_UNLIKELY ( ! pC ) ) {
return ;
}
pC - > deselect ( ) ;
auto its = captureList . begin ( ) ;
auto iti = posList . begin ( ) ;
2023-02-24 09:19:00 +01:00
for ( int position = 1 ; iti ! = posList . end ( ) ; + + iti , + + its , position + + ) {
2023-05-14 15:06:15 +02:00
const int begin = * iti ;
2024-03-11 15:40:56 +00:00
const std : : string & s = * its ;
2023-05-14 15:06:15 +02:00
const int length = QString : : fromStdString ( s ) . size ( ) ;
2022-01-06 21:35:10 +01:00
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
2023-02-24 09:19:00 +01:00
if ( position % numberOfCaptureGroups ! = 1 ) {
2022-01-06 21:35:10 +01:00
pC - > selectSection ( begin , length ) ;
2026-01-11 08:41:59 +01:00
if ( mBgColor ! = QColorConstants : : Transparent ) {
pC - > setBgColor ( r1 , g1 , b1 , 255 ) ;
}
if ( mFgColor ! = QColorConstants : : Transparent ) {
pC - > setFgColor ( r2 , g2 , b2 ) ;
}
2022-01-06 21:35:10 +01:00
}
2026-01-19 18:10:44 +01:00
} else {
2022-01-06 21:35:10 +01:00
pC - > selectSection ( begin , length ) ;
if ( mBgColor ! = QColorConstants : : Transparent ) {
pC - > setBgColor ( r1 , g1 , b1 , 255 ) ;
2026-01-19 18:10:44 +01:00
}
2022-01-06 21:35:10 +01:00
if ( mFgColor ! = QColorConstants : : Transparent ) {
pC - > setFgColor ( r2 , g2 , b2 ) ;
2026-01-19 18:10:44 +01:00
}
2022-01-06 21:35:10 +01:00
}
}
pC - > reset ( ) ;
2026-01-19 18:10:44 +01:00
}
2022-01-06 21:35:10 +01:00
if ( mIsMultiline ) {
updateMultistates ( patternNumber , captureList , posList , & nameGroups ) ;
return ;
2026-07-18 18:39:57 +02:00
}
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 ) {
2026-07-27 20:20:48 +02:00
filter ( s , begin , lineNumber ) ;
2022-01-06 21:35:10 +01:00
}
2026-07-18 18:39:57 +02:00
} else {
2026-07-27 20:20:48 +02:00
filter ( s , begin , lineNumber ) ;
2022-01-06 21:35:10 +01:00
}
}
}
}
2026-07-18 18:39:57 +02:00
return ;
2022-01-06 21:35:10 +01:00
}
2026-01-19 18:10:44 +01:00
}
2022-01-06 21:35:10 +01:00
2026-07-27 20:20:48 +02:00
bool TTrigger : : match_begin_of_line_substring ( const QString & haystack , const QString & needle , int patternNumber , int posOffset , int lineNumber )
2022-01-06 21:35:10 +01:00
{
if ( haystack . startsWith ( needle ) ) {
2026-07-27 20:20:48 +02:00
processBeginOfLine ( needle , patternNumber , posOffset , lineNumber ) ;
2022-01-06 21:35:10 +01:00
return true ;
}
return false ;
}
2026-07-27 20:20:48 +02:00
void TTrigger : : processBeginOfLine ( const QString & needle , int patternNumber , int posOffset , int lineNumber )
2022-01-06 21:35:10 +01:00
{
std : : list < std : : string > captureList ;
std : : list < int > posList ;
captureList . emplace_back ( needle . toUtf8 ( ) . constData ( ) ) ;
posList . push_back ( 0 + posOffset ) ;
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : darkCyan , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) matched. \n " > > mpHost ;
2022-01-06 21:35:10 +01:00
}
2017-06-26 16:46:54 +02:00
if ( mIsColorizerTrigger ) {
2023-05-14 15:06:15 +02:00
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 ( ) ;
2017-06-26 16:46:54 +02:00
TConsole * pC = mpHost - > mpConsole ;
2019-03-13 09:37:15 +01:00
if ( Q_UNLIKELY ( ! pC ) ) {
2022-01-06 21:35:10 +01:00
return ;
2019-03-13 09:37:15 +01:00
}
2017-04-09 19:43:49 +02:00
auto its = captureList . begin ( ) ;
2022-01-06 21:35:10 +01:00
for ( auto iti = posList . begin ( ) ; iti ! = posList . end ( ) ; + + iti , + + its ) {
2023-05-14 15:06:15 +02:00
const int begin = * iti ;
2024-03-11 15:40:56 +00:00
const std : : string & s = * its ;
2023-05-14 15:06:15 +02:00
const int length = QString : : fromStdString ( s ) . size ( ) ;
2022-01-06 21:35:10 +01:00
pC - > selectSection ( begin , length ) ;
if ( mBgColor ! = QColorConstants : : Transparent ) {
pC - > setBgColor ( r1 , g1 , b1 , 255 ) ;
}
if ( mFgColor ! = QColorConstants : : Transparent ) {
2017-06-26 16:46:54 +02:00
pC - > setFgColor ( r2 , g2 , b2 ) ;
2009-04-18 17:19:40 +02:00
}
}
pC - > reset ( ) ;
}
2017-06-26 16:46:54 +02:00
if ( mIsMultiline ) {
2022-01-06 21:35:10 +01:00
updateMultistates ( patternNumber , captureList , posList ) ;
return ;
2026-07-18 18:39:57 +02:00
}
TLuaInterpreter * pL = mpHost - > getLuaInterpreter ( ) ;
pL - > setCaptureGroups ( captureList , posList ) ;
2022-01-06 21:35:10 +01:00
2026-07-18 18:39:57 +02:00
// call lua trigger function with number of matches and matches itselves as arguments
execute ( ) ;
pL - > clearCaptureGroups ( ) ;
if ( mFilterTrigger ) {
if ( ! captureList . empty ( ) ) {
2026-07-27 20:20:48 +02:00
filter ( captureList . front ( ) , posList . front ( ) , lineNumber ) ;
2009-04-18 17:19:40 +02:00
}
2009-04-02 00:20:23 +02:00
}
2009-01-24 02:50:22 +01:00
}
2026-04-29 12:34:30 +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
{
2017-06-26 16:46:54 +02:00
if ( regexNumber = = 0 ) {
2020-11-05 10:56:26 +01:00
// 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 ) ;
2022-09-14 11:51:32 +02:00
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 ) ;
2022-09-14 11:51:32 +02:00
} 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 > > ( ) ) ;
2021-02-12 17:18:06 +01:00
}
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
TDebug ( Qt : : darkYellow , Qt : : black ) < < " match state " < < mConditionMap . size ( ) < < " / " < < mConditionMap . size ( ) < < " condition # " < < regexNumber < < " =true ( " < < regexNumber < < " / "
2022-01-15 11:34:56 +01:00
< < mPatterns . size ( ) < < " ) regex= " < < mPatterns [ regexNumber ] < < " \n "
2021-03-27 21:38:50 +00:00
> > mpHost ;
2009-08-18 17:48:02 +02:00
}
2017-06-26 16:46:54 +02:00
} else {
int k = 0 ;
for ( auto & matchStatePair : mConditionMap ) {
2009-04-03 01:33:48 +02:00
k + + ;
2017-06-26 16:46:54 +02:00
if ( matchStatePair . second - > nextCondition ( ) = = regexNumber ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
TDebug ( Qt : : darkYellow , Qt : : black ) < < " match state " < < k < < " / " < < mConditionMap . size ( ) < < " condition # " < < regexNumber < < " =true ( " < < regexNumber < < " / " < < mPatterns . size ( )
2022-01-15 11:34:56 +01:00
< < " ) regex= " < < mPatterns [ regexNumber ] < < " \n "
2021-03-27 21:38:50 +00:00
> > mpHost ;
2009-08-18 17:48:02 +02:00
}
2017-04-13 03:08:31 +02:00
matchStatePair . second - > conditionMatched ( ) ;
2017-06-26 16:46:54 +02:00
matchStatePair . second - > multiCaptureList . push_back ( captureList ) ;
matchStatePair . second - > multiCapturePosList . push_back ( posList ) ;
2021-02-07 17:21:04 +01:00
if ( nameMatches ! = nullptr ) {
matchStatePair . second - > nameCaptures . push_back ( * nameMatches ) ;
2026-01-06 07:05:35 -06:00
} else {
matchStatePair . second - > nameCaptures . push_back ( QVector < QPair < QString , QString > > ( ) ) ;
2021-02-07 17:21:04 +01:00
}
2009-01-24 02:50:22 +01:00
}
2009-04-03 01:33:48 +02:00
}
}
}
2026-07-27 20:20:48 +02:00
void TTrigger : : filter ( std : : string & capture , int & posOffset , int lineNumber )
2009-04-28 02:52:30 +02:00
{
2018-05-28 22:26:04 +02:00
if ( capture . empty ( ) ) {
2017-06-26 16:46:54 +02:00
return ;
2009-08-18 17:48:02 +02:00
}
2026-01-11 08:41:20 +01:00
const QString text = QString : : fromStdString ( capture ) ;
2017-06-26 16:46:54 +02:00
for ( auto & trigger : * mpMyChildrenList ) {
2026-07-27 20:20:48 +02:00
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 ;
}
2026-07-27 20:20:48 +02:00
bool TTrigger : : match_substring ( const QString & haystack , const QString & needle , int patternNumber , int posOffset , int lineNumber )
2009-04-03 01:33:48 +02:00
{
2023-05-14 15:06:15 +02:00
const int where = haystack . indexOf ( needle ) ;
2017-06-26 16:46:54 +02:00
if ( where ! = - 1 ) {
2026-07-27 20:20:48 +02:00
processSubstringMatch ( haystack , needle , patternNumber , posOffset , where , lineNumber ) ;
2022-01-06 21:35:10 +01:00
return true ;
}
return false ;
}
2026-07-27 20:20:48 +02:00
void TTrigger : : processSubstringMatch ( const QString & haystack , const QString & needle , int regexNumber , int posOffset , int where , int lineNumber )
2022-01-06 21:35:10 +01:00
{
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
}
2022-01-06 21:35:10 +01:00
}
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : cyan , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( regexNumber ) < < " ) matched. \n " > > mpHost ;
2022-01-06 21:35:10 +01:00
}
if ( mIsColorizerTrigger ) {
2023-05-14 15:06:15 +02:00
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 ( ) ;
2022-01-06 21:35:10 +01:00
TConsole * pC = mpHost - > mpConsole ;
if ( Q_UNLIKELY ( ! pC ) ) {
return ;
2017-06-26 16:46:54 +02:00
}
2022-01-06 21:35:10 +01:00
pC - > deselect ( ) ;
auto its = captureList . begin ( ) ;
for ( auto iti = posList . begin ( ) ; iti ! = posList . end ( ) ; + + iti , + + its ) {
2023-05-14 15:06:15 +02:00
const int begin = * iti ;
2024-03-11 15:40:56 +00:00
const std : : string & s = * its ;
2023-05-14 15:06:15 +02:00
const int length = QString : : fromStdString ( s ) . size ( ) ;
2022-01-06 21:35:10 +01:00
pC - > selectSection ( begin , length ) ;
if ( mBgColor ! = QColorConstants : : Transparent ) {
pC - > setBgColor ( r1 , g1 , b1 , 255 ) ;
}
if ( mFgColor ! = QColorConstants : : Transparent ) {
pC - > setFgColor ( r2 , g2 , b2 ) ;
2009-04-18 17:19:40 +02:00
}
}
2022-01-06 21:35:10 +01:00
pC - > reset ( ) ;
}
if ( mIsMultiline ) {
updateMultistates ( regexNumber , captureList , posList ) ;
return ;
2026-07-18 18:39:57 +02:00
}
TLuaInterpreter * pL = mpHost - > getLuaInterpreter ( ) ;
pL - > setCaptureGroups ( captureList , posList ) ;
2009-04-18 17:19:40 +02:00
2026-07-18 18:39:57 +02:00
// call lua trigger function with number of matches and matches itselves as arguments
execute ( ) ;
pL - > clearCaptureGroups ( ) ;
if ( mFilterTrigger ) {
if ( ! captureList . empty ( ) ) {
2026-07-27 20:20:48 +02:00
filter ( captureList . front ( ) , posList . front ( ) , lineNumber ) ;
2009-04-18 17:19:40 +02:00
}
2010-03-18 16:07:12 +01:00
}
2009-01-24 02:50:22 +01:00
}
2026-07-27 20:20:48 +02:00
bool TTrigger : : match_color_pattern ( int line , int patternNumber , int posOffset , int length )
2009-05-22 16:37:38 +02:00
{
2022-01-06 21:35:10 +01:00
if ( patternNumber > = mColorPatternList . size ( ) ) {
2017-06-26 16:46:54 +02:00
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 ;
2017-06-26 16:46:54 +02:00
if ( line > = static_cast < int > ( mpHost - > mpConsole - > buffer . buffer . size ( ) ) ) {
return false ;
}
std : : deque < TChar > & bufferLine = mpHost - > mpConsole - > buffer . buffer [ line ] ;
2023-05-14 15:06:15 +02:00
const QString & lineBuffer = mpHost - > mpConsole - > buffer . lineBuffer [ line ] ;
2026-07-29 17:42:35 +02:00
// 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 ) ;
2026-07-27 20:20:48 +02:00
// 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 ;
2009-11-04 00:33:42 +01:00
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 ( ) ;
2017-06-26 16:46:54 +02:00
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
2017-06-26 16:46:54 +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 ( 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
}
2026-07-27 20:20:48 +02:00
for ( auto it = bufferLine . begin ( ) + start ; pos < end ; + + it , + + pos ) {
2026-07-29 17:42:35 +02:00
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:
2026-07-29 17:42:35 +02:00
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 ( ) ) ) ) {
2017-06-26 16:46:54 +02:00
if ( matchBegin = = - 1 ) {
2009-06-04 10:27:08 +02:00
matchBegin = pos ;
2017-06-26 16:46:54 +02:00
}
2009-06-04 10:27:08 +02:00
matching = true ;
2017-06-26 16:46:54 +02:00
} 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
2026-07-27 20:20:48 +02:00
if ( ( ! matching ) | | ( matching & & ( pos + 1 > = end ) ) ) {
2017-06-26 16:46:54 +02:00
if ( matchBegin > - 1 ) {
2010-03-18 16:07:12 +01:00
std : : string got ;
2017-06-26 16:46:54 +02:00
if ( matching ) {
2018-02-28 01:03:48 +00:00
got = lineBuffer . mid ( matchBegin , pos - matchBegin + 1 ) . toUtf8 ( ) . constData ( ) ;
2017-06-26 16:46:54 +02:00
} else {
2018-02-28 01:03:48 +00:00
got = lineBuffer . mid ( matchBegin , pos - matchBegin ) . toUtf8 ( ) . constData ( ) ;
2017-06-26 16:46:54 +02:00
}
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
}
2017-06-26 16:46:54 +02:00
if ( canExecute ) {
2026-07-27 20:20:48 +02:00
processColorPattern ( patternNumber , captureList , posList , line ) ;
2022-01-06 21:35:10 +01:00
return true ;
}
return false ;
}
2026-07-27 20:20:48 +02:00
void TTrigger : : processColorPattern ( int patternNumber , std : : list < std : : string > & captureList , std : : list < int > & posList , int lineNumber )
2022-01-06 21:35:10 +01:00
{
if ( mIsColorizerTrigger ) {
2023-05-14 15:06:15 +02:00
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 ( ) ;
2022-01-06 21:35:10 +01:00
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 ) {
2023-05-14 15:06:15 +02:00
const int begin = * iti ;
2022-01-06 21:35:10 +01:00
// qDebug() << "TTrigger::match_color_pattern(" << line << "," << patternNumber << ") INFO - match found: " << (*its).c_str() << " size is:" << (*its).size();
2024-03-11 15:40:56 +00:00
const std : : string & s = * its ;
2023-05-14 15:06:15 +02:00
const int length = QString : : fromStdString ( s ) . size ( ) ;
2022-01-06 21:35:10 +01:00
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
}
}
2022-01-06 21:35:10 +01:00
pC - > reset ( ) ;
}
if ( mIsMultiline ) {
updateMultistates ( patternNumber , captureList , posList ) ;
return ;
2026-07-18 18:39:57 +02:00
}
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 + + ) {
2026-07-27 20:20:48 +02:00
filter ( * it1 , * it2 , lineNumber ) ;
2009-05-22 16:37:38 +02:00
}
}
}
}
2022-01-06 21:35:10 +01:00
bool TTrigger : : match_line_spacer ( int patternNumber )
2009-10-05 18:46:31 +02:00
{
2017-06-26 16:46:54 +02:00
if ( mIsMultiline ) {
int k = 0 ;
2010-03-15 09:37:16 +01:00
2017-06-26 16:46:54 +02:00
for ( auto & matchStatePair : mConditionMap ) {
2009-10-05 18:46:31 +02:00
k + + ;
2022-01-06 21:35:10 +01:00
if ( matchStatePair . second - > nextCondition ( ) = = patternNumber ) {
2022-01-15 11:34:56 +01:00
if ( matchStatePair . second - > lineSpacerMatch ( mPatterns . value ( patternNumber ) . toInt ( ) ) ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : yellow , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) condition # " < < patternNumber < < " =true " > > mpHost ;
2022-01-06 21:35:10 +01:00
TDebug ( Qt : : darkYellow , Qt : : black ) < < TDebug : : csmContinue < < " match state " < < k < < " / " < < mConditionMap . size ( ) < < " condition # " < < patternNumber < < " =true ( "
2022-01-15 11:34:56 +01:00
< < patternNumber + 1 < < " / " < < mPatterns . size ( ) < < " ) line spacer= " < < mPatterns . value ( patternNumber ) < < " lines \n "
2022-01-06 21:35:10 +01:00
> > mpHost ;
2009-10-05 18:46:31 +02:00
}
2017-04-13 03:08:31 +02:00
matchStatePair . second - > conditionMatched ( ) ;
2023-05-14 15:06:15 +02:00
std : : list < std : : string > const captureList ;
std : : list < int > const posList ;
2017-06-26 16:46:54 +02:00
matchStatePair . second - > multiCaptureList . push_back ( captureList ) ;
matchStatePair . second - > multiCapturePosList . push_back ( posList ) ;
2026-01-06 07:05:35 -06:00
matchStatePair . second - > nameCaptures . push_back ( QVector < QPair < QString , QString > > ( ) ) ;
2009-10-05 18:46:31 +02:00
}
}
}
}
2010-12-28 23:31:03 +01:00
return true ; //line spacers don't make sense outside of AND triggers -> ignore them
2009-10-05 18:46:31 +02:00
}
2022-01-06 21:35:10 +01:00
bool TTrigger : : match_lua_code ( int patternNumber )
2009-04-02 00:20:23 +02:00
{
2022-01-06 21:35:10 +01:00
if ( mLuaConditionMap . find ( patternNumber ) = = mLuaConditionMap . end ( ) ) {
2017-06-26 16:46:54 +02:00
return false ;
}
2009-04-02 00:20:23 +02:00
2022-01-06 21:35:10 +01:00
if ( mpLua - > callConditionFunction ( mLuaConditionMap [ patternNumber ] , mName ) ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : yellow , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) matched. \n " > > mpHost ;
2017-06-26 16:46:54 +02:00
}
if ( mIsMultiline ) {
2009-04-03 01:33:48 +02:00
std : : list < std : : string > captureList ;
std : : list < int > posList ;
2022-01-06 21:35:10 +01:00
updateMultistates ( patternNumber , captureList , posList ) ;
2009-04-03 01:33:48 +02:00
return true ;
2009-04-02 00:20:23 +02:00
}
execute ( ) ;
return true ;
}
return false ;
}
2017-11-02 21:16:57 +01:00
bool TTrigger : : match_prompt ( int patternNumber )
{
if ( mpHost - > mpConsole - > mIsPromptLine ) {
2022-01-06 21:35:10 +01:00
processPromptMatch ( patternNumber ) ;
2017-11-02 21:16:57 +01:00
return true ;
}
return false ;
}
2022-01-06 21:35:10 +01:00
void TTrigger : : processPromptMatch ( int patternNumber )
2009-01-24 02:50:22 +01:00
{
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : yellow , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) matched. \n " > > mpHost ;
2017-06-26 16:46:54 +02:00
}
2022-01-06 21:35:10 +01:00
if ( mIsMultiline ) {
2009-04-03 01:33:48 +02:00
std : : list < std : : string > captureList ;
std : : list < int > posList ;
2022-01-06 21:35:10 +01:00
updateMultistates ( patternNumber , captureList , posList ) ;
return ;
}
execute ( ) ;
}
2026-07-27 20:20:48 +02:00
bool TTrigger : : match_exact_match ( const QString & haystack , const QString & needle , int patternNumber , int posOffset , int lineNumber )
2022-01-06 21:35:10 +01:00
{
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 ) ;
2022-01-06 21:35:10 +01:00
if ( text . endsWith ( QChar ( ' \n ' ) ) ) {
text . chop ( 1 ) ;
}
if ( text = = needle ) {
2026-07-27 20:20:48 +02:00
processExactMatch ( needle , patternNumber , posOffset , lineNumber ) ;
2022-01-06 21:35:10 +01:00
return true ;
}
return false ;
}
2026-07-27 20:20:48 +02:00
void TTrigger : : processExactMatch ( const QString & needle , int patternNumber , int posOffset , int lineNumber )
2022-01-06 21:35:10 +01:00
{
std : : list < std : : string > captureList ;
std : : list < int > posList ;
2026-07-27 20:20:48 +02:00
captureList . emplace_back ( needle . toUtf8 ( ) . constData ( ) ) ;
2022-01-06 21:35:10 +01:00
posList . push_back ( 0 + posOffset ) ;
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2022-01-15 11:34:56 +01:00
TDebug ( Qt : : yellow , Qt : : black ) < < " Trigger name= " < < mName < < " ( " < < mPatterns . value ( patternNumber ) < < " ) matched. \n " > > mpHost ;
2022-01-06 21:35:10 +01:00
}
if ( mIsColorizerTrigger ) {
2023-05-14 15:06:15 +02:00
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 ( ) ;
2022-01-06 21:35:10 +01:00
TConsole * pC = mpHost - > mpConsole ;
if ( Q_UNLIKELY ( ! pC ) ) {
return ;
2017-06-26 16:46:54 +02:00
}
2022-01-06 21:35:10 +01:00
auto its = captureList . begin ( ) ;
for ( auto iti = posList . begin ( ) ; iti ! = posList . end ( ) ; + + iti , + + its ) {
2023-05-14 15:06:15 +02:00
const int begin = * iti ;
2024-03-11 15:40:56 +00:00
const std : : string & s = * its ;
2023-05-14 15:06:15 +02:00
const int length = QString : : fromStdString ( s ) . size ( ) ;
2022-01-06 21:35:10 +01:00
pC - > selectSection ( begin , length ) ;
if ( mBgColor ! = QColorConstants : : Transparent ) {
pC - > setBgColor ( r1 , g1 , b1 , 255 ) ;
}
if ( mFgColor ! = QColorConstants : : Transparent ) {
pC - > setFgColor ( r2 , g2 , b2 ) ;
2009-04-18 17:19:40 +02:00
}
}
2022-01-06 21:35:10 +01:00
pC - > reset ( ) ;
}
if ( mIsMultiline ) {
updateMultistates ( patternNumber , captureList , posList ) ;
return ;
2026-07-18 18:39:57 +02:00
}
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 ( ) ) {
2026-07-27 20:20:48 +02:00
filter ( captureList . front ( ) , posList . front ( ) , lineNumber ) ;
2009-04-18 17:19:40 +02:00
}
2010-03-18 16:07:12 +01:00
}
2009-01-24 02:50:22 +01:00
}
2022-01-15 11:34:56 +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
2022-01-06 21:35:10 +01:00
bool TTrigger : : match ( char * haystackC , const QString & haystack , int line , int posOffset )
2009-01-24 02:50:22 +01:00
{
2026-01-25 08:54:56 +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 ;
2017-06-26 16:46:54 +02:00
if ( isActive ( ) ) {
if ( mIsLineTrigger ) {
if ( - - mStartOfLineDelta < 0 ) {
2009-02-16 17:22:00 +01:00
execute ( ) ;
2017-06-26 16:46:54 +02:00
if ( - - mLineDelta < = 0 ) {
2009-05-03 16:23:51 +02:00
deactivate ( ) ;
2017-06-26 16:46:54 +02:00
mpHost - > getTriggerUnit ( ) - > markCleanup ( this ) ;
2009-05-03 16:23:51 +02:00
}
2009-01-24 02:50:22 +01:00
return true ;
}
return false ;
}
2010-03-18 16:07:12 +01:00
2022-10-02 09:43:20 +01:00
if ( haystack . isEmpty ( ) ) {
2009-02-26 09:04:26 +01:00
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 ;
2017-06-26 16:46:54 +02:00
if ( mIsMultiline ) {
for ( auto & matchStatePair : mConditionMap ) {
2017-04-13 03:08:31 +02:00
matchStatePair . second - > newLineArrived ( ) ;
2023-05-14 15:06:15 +02:00
const int next = matchStatePair . second - > nextCondition ( ) ;
2017-06-26 16:46:54 +02:00
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
}
2009-04-02 00:20:23 +02:00
2023-05-14 15:06:15 +02:00
const int size = mPatternKinds . size ( ) ;
2017-11-02 21:16:57 +01:00
for ( int patternNumber = 0 ; ; patternNumber + + ) {
if ( patternNumber > = size ) {
2017-06-26 16:46:54 +02:00
break ;
}
2009-02-12 06:18:08 +01:00
ret = false ;
2022-01-15 11:34:56 +01:00
switch ( mPatternKinds . value ( patternNumber ) ) {
2017-06-26 16:46:54 +02:00
case REGEX_SUBSTRING :
2026-07-27 20:20:48 +02:00
ret = match_substring ( haystack , mPatterns . at ( patternNumber ) , patternNumber , posOffset , line ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_PERL :
2026-07-27 20:20:48 +02:00
ret = match_perl ( haystackC , haystack , patternNumber , posOffset , line ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_BEGIN_OF_LINE_SUBSTRING :
2026-07-27 20:20:48 +02:00
ret = match_begin_of_line_substring ( haystack , mPatterns . at ( patternNumber ) , patternNumber , posOffset , line ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_EXACT_MATCH :
2026-07-27 20:20:48 +02:00
ret = match_exact_match ( haystack , mPatterns . at ( patternNumber ) , patternNumber , posOffset , line ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_LUA_CODE :
2017-11-02 21:16:57 +01:00
ret = match_lua_code ( patternNumber ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_LINE_SPACER :
2017-11-02 21:16:57 +01:00
ret = match_line_spacer ( patternNumber ) ;
2017-06-26 16:46:54 +02:00
break ;
case REGEX_COLOR_PATTERN :
2026-07-27 20:20:48 +02:00
// 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 ( ) ) ) ;
2017-11-02 21:16:57 +01:00
break ;
case REGEX_PROMPT :
ret = match_prompt ( patternNumber ) ;
2017-06-26 16:46:54 +02:00
break ;
2009-01-24 02:50:22 +01:00
}
2009-04-22 00:43:49 +02: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
2017-06-26 16:46:54 +02:00
if ( ! mIsMultiline ) {
if ( ret ) {
2009-02-11 02:42:27 +01:00
conditionMet = true ;
2009-08-18 17:48:02 +02:00
mKeepFiring = mStayOpen ;
2010-03-18 16:07:12 +01:00
break ;
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
} else {
2017-11-02 21:16:57 +01:00
if ( ( ! ret ) & & ( patternNumber > = highestCondition ) ) {
2017-06-26 16:46:54 +02:00
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
2017-06-26 16:46:54 +02:00
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
2019-07-25 12:05:26 +02:00
std : : list < TMatchState * > removeList ;
2010-03-18 16:07:12 +01:00
2017-06-26 16:46:54 +02:00
for ( auto & matchStatePair : mConditionMap ) {
2009-02-11 02:42:27 +01:00
k + + ;
2017-06-26 16:46:54 +02:00
if ( matchStatePair . second - > isComplete ( ) ) {
2009-08-18 17:48:02 +02:00
mKeepFiring = mStayOpen ;
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 ;
2017-06-26 16:46:54 +02:00
}
removeList . push_back ( matchStatePair . first ) ;
2009-03-26 02:07:45 +01:00
conditionMet = true ;
2017-06-26 16:46:54 +02:00
TLuaInterpreter * pL = mpHost - > getLuaInterpreter ( ) ;
2021-02-07 17:21:04 +01:00
pL - > setMultiCaptureGroups ( matchStatePair . second - > multiCaptureList , matchStatePair . second - > multiCapturePosList , matchStatePair . second - > nameCaptures ) ;
2009-03-26 02:07:45 +01:00
execute ( ) ;
pL - > clearCaptureGroups ( ) ;
2017-06-26 16:46:54 +02:00
if ( mFilterTrigger ) {
std : : list < std : : list < std : : string > > multiCaptureList ;
2017-04-13 03:08:31 +02:00
multiCaptureList = matchStatePair . second - > multiCaptureList ;
2018-05-28 22:26:04 +02:00
if ( ! multiCaptureList . empty ( ) ) {
2017-06-26 16:46:54 +02:00
for ( auto mit = multiCaptureList . begin ( ) ; mit ! = multiCaptureList . end ( ) ; mit + + , k + + ) {
2023-05-14 15:06:15 +02:00
const int total = ( * mit ) . size ( ) ;
2017-04-09 19:43:49 +02:00
auto its = ( * mit ) . begin ( ) ;
2017-06-26 16:46:54 +02:00
for ( int i = 1 ; its ! = ( * mit ) . end ( ) ; + + its , i + + ) {
2009-06-24 23:10:50 +02:00
std : : string s = * its ;
int p = 0 ;
2026-07-27 20:20:48 +02:00
// multiline captures may come from earlier lines, so no
// single line number applies here
2017-06-26 16:46:54 +02:00
if ( total > 1 ) {
if ( i % total ! = 1 ) {
2026-07-27 20:20:48 +02:00
filter ( s , p , - 1 ) ;
2009-06-24 23:10:50 +02:00
}
2017-06-26 16:46:54 +02:00
} else {
2026-07-27 20:20:48 +02:00
filter ( s , p , - 1 ) ;
2009-06-24 23:10:50 +02:00
}
}
}
}
}
2009-01-24 02:50:22 +01:00
}
2010-03-18 16:07:12 +01:00
2017-06-26 16:46:54 +02:00
if ( ! matchStatePair . second - > newLine ( ) ) {
removeList . push_back ( matchStatePair . first ) ;
2009-01-24 02:50:22 +01:00
}
}
2017-06-26 16:46:54 +02:00
for ( auto & matchState : removeList ) {
if ( mConditionMap . find ( matchState ) ! = mConditionMap . end ( ) ) {
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
}
2017-06-26 16:46:54 +02:00
mConditionMap . erase ( matchState ) ;
2009-02-12 06:18:08 +01:00
}
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
2017-06-26 16:46:54 +02:00
if ( ! mFilterTrigger ) {
2022-01-15 11:34:56 +01:00
if ( conditionMet | | ( mPatterns . empty ( ) ) ) {
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
2025-10-20 14:32:52 +02:00
ret = trigger - > match ( haystackC , haystack , line , posOffset ) ;
2017-06-26 16:46:54 +02:00
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
2017-06-26 16:46:54 +02:00
if ( ( mKeepFiring > 0 ) & & ( ! conditionMet ) ) {
2009-11-27 23:12:12 +01:00
mKeepFiring - - ;
2018-05-28 22:26:04 +02:00
if ( ( mKeepFiring = = mStayOpen ) | | ( mpMyChildrenList - > empty ( ) ) ) {
2009-11-27 23:12:12 +01:00
execute ( ) ;
}
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
2025-10-20 14:32:52 +02:00
ret = trigger - > match ( haystackC , haystack , line , posOffset ) ;
2017-06-26 16:46:54 +02:00
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 ) ;
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
// FIXME: This message is translated - but most other TDebug ones are not!
2022-10-03 07:43:55 +02:00
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
}
2021-03-27 21:38:50 +00:00
2022-12-12 11:51:28 +00:00
} else if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
// FIXME: This message is translated - but most other TDebug ones are not!
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 ;
}
fix: New Triggers, Aliases, and Scripts can now be disabled (#7945)
#### Brief overview of PR changes/additions
This is meant to solve issue #7723. In order to allow triggers, aliases,
and scripts named "New trigger", "New alias", and "New script" to be
disabled, I added new variables and functions in the TTrigger, TAlias,
and TScript classes. These functions allow one to see whether the most
recent save was the "save" that created the trigger/alias/script; if it
is, then while saving, the variable is changed.
#### Motivation for adding to Mudlet
#### Other info (issues closed, discussion etc)
This is my second pull request. Please let me know if there is any way I
can improve it.
2025-07-23 08:54:59 -05:00
bool TTrigger : : checkIfNew ( )
{
2025-08-16 13:55:01 +01:00
return mIsNew ;
fix: New Triggers, Aliases, and Scripts can now be disabled (#7945)
#### Brief overview of PR changes/additions
This is meant to solve issue #7723. In order to allow triggers, aliases,
and scripts named "New trigger", "New alias", and "New script" to be
disabled, I added new variables and functions in the TTrigger, TAlias,
and TScript classes. These functions allow one to see whether the most
recent save was the "save" that created the trigger/alias/script; if it
is, then while saving, the variable is changed.
#### Motivation for adding to Mudlet
#### Other info (issues closed, discussion etc)
This is my second pull request. Please let me know if there is any way I
can improve it.
2025-07-23 08:54:59 -05:00
}
void TTrigger : : unmarkAsNew ( )
{
2025-08-16 13:55:01 +01:00
mIsNew = false ;
fix: New Triggers, Aliases, and Scripts can now be disabled (#7945)
#### Brief overview of PR changes/additions
This is meant to solve issue #7723. In order to allow triggers, aliases,
and scripts named "New trigger", "New alias", and "New script" to be
disabled, I added new variables and functions in the TTrigger, TAlias,
and TScript classes. These functions allow one to see whether the most
recent save was the "save" that created the trigger/alias/script; if it
is, then while saving, the variable is changed.
#### Motivation for adding to Mudlet
#### Other info (issues closed, discussion etc)
This is my second pull request. Please let me know if there is any way I
can improve it.
2025-07-23 08:54:59 -05:00
}
2009-11-04 00:33:42 +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
// 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 )
2009-11-04 00:33:42 +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
/*
* 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
*/
2024-03-11 15:40:56 +00:00
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
2020-05-02 23:49:36 +01:00
if ( ! ( fgColor . isValid ( ) | | bgColor . isValid ( ) ) ) {
2017-08-03 08:46:00 +02:00
return nullptr ;
2017-06-26 16:46:54 +02:00
}
2009-11-04 00:33:42 +01:00
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 ) ;
2017-06-26 16:46:54 +02:00
if ( ! pCT ) {
2017-08-03 08:46:00 +02:00
return nullptr ;
2017-06-26 16:46:54 +02:00
}
2009-11-04 00:33:42 +01:00
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 ;
2009-11-04 00:33:42 +01:00
return pCT ;
}
2017-06-26 16:46:54 +02:00
bool TTrigger : : setupColorTrigger ( int ansiFg , int ansiBg )
2009-11-04 00:33:42 +01:00
{
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 ) ;
2017-06-26 16:46:54 +02:00
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
2017-06-26 16:46:54 +02:00
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 ) ) ;
2009-11-04 00:33:42 +01:00
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
2017-06-26 16:46:54 +02:00
bool TTrigger : : setupTmpColorTrigger ( int ansiFg , int ansiBg )
2009-11-04 00:33:42 +01:00
{
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 ) ;
2017-06-26 16:46:54 +02:00
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
2024-11-04 06:55:05 +00:00
// createColorPatternText(...) now returns an empty string if BOTH color
// codes are the scmIgnored ones:
2022-01-15 11:34:56 +01:00
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 ) ) ;
2009-11-04 00:33:42 +01:00
return true ;
}
2009-02-11 19:16:08 +01:00
bool TTrigger : : isFilterChain ( )
{
2022-01-15 11:34:56 +01:00
return ( ! mPatterns . empty ( ) ) & & ( hasChildren ( ) ) ;
2009-02-11 19:16:08 +01:00
}
2009-01-24 02:50:22 +01:00
bool TTrigger : : registerTrigger ( )
{
2017-06-26 16:46:54 +02:00
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 ;
2017-06-26 16:46:54 +02:00
if ( ! compileScript ( ) ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
TDebug ( Qt : : white , Qt : : red ) < < " ERROR: Lua compile error. compiling script of Trigger: " < < mName < < " \n " > > mpHost ;
2017-06-26 16:46:54 +02:00
}
2010-08-25 00:41:43 +02:00
mOK_code = false ;
}
2022-01-15 11:34:56 +01:00
setRegexCodeList ( mPatterns , mPatternKinds ) ;
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
2017-04-13 03:08:31 +02:00
trigger - > compileAll ( ) ;
2010-08-25 00:41:43 +02:00
}
}
2009-01-24 02:50:22 +01:00
void TTrigger : : compile ( )
{
2017-06-26 16:46:54 +02:00
if ( mNeedsToBeCompiled ) {
if ( ! compileScript ( ) ) {
2022-12-12 11:51:28 +00:00
if ( mudlet : : smDebugMode ) {
2021-03-27 21:38:50 +00:00
TDebug ( Qt : : white , Qt : : red ) < < " ERROR: Lua compile error. compiling script of Trigger: " < < mName < < " \n " > > mpHost ;
2017-06-26 16:46:54 +02:00
}
2009-04-09 21:42:11 +02:00
mOK_code = false ;
2009-01-24 02:50:22 +01:00
}
}
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
2017-04-13 03:08:31 +02:00
trigger - > compile ( ) ;
2009-01-24 02:50:22 +01:00
}
}
2017-06-26 16:46:54 +02:00
bool TTrigger : : setScript ( const QString & script )
2009-01-24 02:50:22 +01:00
{
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 ;
2017-10-12 06:10:33 +02:00
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 ( )
{
2021-12-07 06:21:39 +01:00
mFuncName = qsl ( " Trigger%1 " ) . arg ( QString : : number ( mID ) ) ;
improve error messages by making code start on first line (#6855)
<!-- Keep the title short & concise so anyone non-technical can
understand it,
the title appears in PTB changelogs -->
#### Brief overview of PR changes/additions
Behind the scenes there are things like `code = qsl("function Alias%1()
%2\nend").arg(id, code)` which handles the code of an alias and embeds
it into a function. Timers, triggers, and keybinds all have similar, but
with the `function X()` on a line alone. When they get compiled, the
first line of an alias code box is also the first line of the resulting
function, so an error on the first line of the edit box code is also the
first line of the post-embed code. But for the other type of items, the
first line of edit box is second line of post-embed code. When
compiling, the system is looking at the post-embed code, so it gives
errors with line numbers that make sense with aliases but are confusing
with the others.
This edit should make them all similar to aliases.
#### Motivation for adding to Mudlet
fix #1460
#### Other info (issues closed, discussion etc)
Error messages say things like "near X" instead of citing column
numbers, so I don't think there are any negative consequences for first
line being on same line after `function X()`. It's how aliases are
handled already.
---------
Co-authored-by: Stephen Lyons <slysven@virginmedia.com>
2023-05-30 13:20:31 -04:00
const QString code = qsl ( " function %1() %2 \n end " ) . arg ( mFuncName , mScript ) ;
2009-04-09 21:42:11 +02:00
QString error ;
2021-12-07 06:21:39 +01:00
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 ;
}
2026-07-18 18:39:57 +02:00
mOK_code = false ;
setError ( error ) ;
return false ;
2009-04-09 21:42:11 +02:00
}
2009-04-02 00:20:23 +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
2017-06-26 16:46:54 +02:00
if ( mSoundTrigger ) { /* eventually something should be added to the gui to change sound volumes. 100=full volume */
2022-02-20 01:06:50 -05:00
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 ) ;
2009-05-09 14:36:12 +02:00
}
2022-10-02 09:43:20 +01:00
if ( ! mCommand . isEmpty ( ) ) {
2017-06-26 16:46:54 +02:00
mpHost - > send ( mCommand ) ;
2009-02-09 00:55:01 +01:00
}
2017-06-26 16:46:54 +02:00
if ( mNeedsToBeCompiled ) {
if ( ! compileScript ( ) ) {
2009-04-04 00:33:09 +02:00
return ;
2009-04-09 21:42:11 +02:00
}
2009-03-20 19:43:29 +01:00
}
2017-10-12 06:10:33 +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 + + ;
}
}
2017-10-12 06:10:33 +02:00
return ;
}
if ( mScript . isEmpty ( ) ) {
return ;
}
2017-06-26 16:46:54 +02:00
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 + + ;
}
}
2017-06-26 16:46:54 +02:00
} 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
}
}
2017-06-26 16:46:54 +02:00
void TTrigger : : enableTrigger ( const QString & name )
2009-01-24 02:50:22 +01:00
{
2017-06-26 16:46:54 +02:00
if ( mName = = name ) {
setIsActive ( true ) ;
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
trigger - > enableTrigger ( name ) ;
2009-01-24 02:50:22 +01:00
}
}
2017-06-26 16:46:54 +02:00
void TTrigger : : disableTrigger ( const QString & name )
2009-01-24 02:50:22 +01:00
{
2017-06-26 16:46:54 +02:00
if ( mName = = name ) {
setIsActive ( false ) ;
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
trigger - > disableTrigger ( name ) ;
2009-01-24 02:50:22 +01:00
}
}
2017-06-26 16:46:54 +02:00
TTrigger * TTrigger : : killTrigger ( const QString & name )
2009-01-24 02:50:22 +01:00
{
2017-06-26 16:46:54 +02:00
if ( mName = = name ) {
setIsActive ( false ) ;
2009-01-24 02:50:22 +01:00
}
2017-06-26 16:46:54 +02:00
for ( auto trigger : * mpMyChildrenList ) {
trigger - > killTrigger ( name ) ;
2009-01-24 02:50:22 +01:00
}
2017-08-03 08:46:00 +02: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 {
2021-12-07 06:21:39 +01:00
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 {
2021-12-07 06:21:39 +01:00
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
}
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)
2024-03-11 15:40:56 +00:00
const QRegularExpression regex = QRegularExpression ( qsl ( " ^ANSI_COLORS_F{( \\ d+|DEFAULT|IGNORE)}_B{( \\ d+|DEFAULT|IGNORE)}$ " ) ) ;
2021-12-07 06:21:39 +01:00
// Was QRegularExpression regex = QRegularExpression(qsl(R"(FG(\d+)BG(\d+))"));
2024-03-11 15:40:56 +00:00
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 ;
}
}
2024-12-25 09:07:33 +01:00
QString TTrigger : : packageName ( TTrigger * pTrigger )
{
if ( ! pTrigger ) {
return QString ( ) ;
}
if ( ! pTrigger - > mPackageName . isEmpty ( ) ) {
2026-04-12 17:51:58 +02:00
return ! mpHost - > mInstalledModules . contains ( pTrigger - > mPackageName ) ? pTrigger - > mPackageName : QString ( ) ;
2024-12-25 09:07:33 +01:00
}
if ( pTrigger - > getParent ( ) ) {
return packageName ( pTrigger - > getParent ( ) ) ;
}
return QString ( ) ;
}
QString TTrigger : : moduleName ( TTrigger * pTrigger )
{
if ( ! pTrigger ) {
return QString ( ) ;
}
if ( ! pTrigger - > mPackageName . isEmpty ( ) ) {
2026-04-12 17:51:58 +02:00
return mpHost - > mInstalledModules . contains ( pTrigger - > mPackageName ) ? pTrigger - > mPackageName : QString ( ) ;
2024-12-25 09:07:33 +01:00
}
if ( pTrigger - > getParent ( ) ) {
return moduleName ( pTrigger - > getParent ( ) ) ;
}
return QString ( ) ;
}