{"id":15017135,"url":"https://github.com/poti1/runtime-debugger","last_synced_at":"2025-04-09T19:42:35.709Z","repository":{"id":124116037,"uuid":"567636357","full_name":"poti1/runtime-debugger","owner":"poti1","description":"Simple runtime debugger for perl","archived":false,"fork":false,"pushed_at":"2025-02-06T09:26:09.000Z","size":233,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-23T21:45:42.030Z","etag":null,"topics":["debugging","hacktoberfest","perl","perl5"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/poti1.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-18T08:17:37.000Z","updated_at":"2025-02-05T14:27:24.000Z","dependencies_parsed_at":"2024-05-08T08:29:00.223Z","dependency_job_id":"ed05b24a-e717-4607-a982-fbd677cdcbef","html_url":"https://github.com/poti1/runtime-debugger","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poti1%2Fruntime-debugger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poti1%2Fruntime-debugger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poti1%2Fruntime-debugger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poti1%2Fruntime-debugger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/poti1","download_url":"https://codeload.github.com/poti1/runtime-debugger/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248101161,"owners_count":21047915,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debugging","hacktoberfest","perl","perl5"],"created_at":"2024-09-24T19:49:56.192Z","updated_at":"2025-04-09T19:42:35.703Z","avatar_url":"https://github.com/poti1.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LOGO\n\n     ____              _   _\n    |  _ \\ _   _ _ __ | |_(_)_ __ ___   ___\n    | |_) | | | | '_ \\| __| | '_ ` _ \\ / _ \\\n    |  _ \u003c| |_| | | | | |_| | | | | | |  __/\n    |_| \\_\\\\__,_|_| |_|\\__|_|_| |_| |_|\\___|\n\n     ____       _\n    |  _ \\  ___| |__  _   _  __ _  __ _  ___ _ __\n    | | | |/ _ \\ '_ \\| | | |/ _` |/ _` |/ _ \\ '__|\n    | |_| |  __/ |_) | |_| | (_| | (_| |  __/ |\n    |____/ \\___|_.__/ \\__,_|\\__, |\\__, |\\___|_|\n                            |___/ |___/\n\n# NAME\n\nRuntime::Debugger - Easy to use REPL with existing lexical support and DWIM tab completion.\n\n(emphasis on \"existing\" since I have not yet found this support in other modules).\n\n# SYNOPSIS\n\nIn a script:\n\n    use Runtime::Debugger;\n    repl;\n\nOn the commandline:\n\n    perl -MRuntime::Debugger -E 'repl'\n\nSame, but with some variables to play with:\n\n    perl -MRuntime::Debugger -E 'my $str1 = \"Func\"; our $str2 = \"Func2\"; my @arr1 = \"arr-1\"; our @arr2 = \"arr-2\"; my %hash1 = qw(hash 1); our %hash2 = qw(hash 2); my $coderef = sub { \"code-ref: @_\" }; {package My; sub Func{\"My-Func\"} sub Func2{\"My-Func2\"}} my $obj = bless {}, \"My\"; repl; say $@'\n\nFrom another script/function:\n\n    my $var_to_find = 111;\n\n    sub other {\n        use Runtime::Debugger;\n        repl( levels_up =\u003e 1 );\n    }\n\n# DESCRIPTION\n\n\"What? Another debugger? What about ... ?\"\n\n## Other Modules\n\n### perl5db.pl\n\nThe standard perl debugger (`perl5db.pl`) is a powerful tool.\n\nUsing `per5db.pl`, one would normally be able to do this:\n\n    # Insert a breakpoint in your code:\n    $DB::single = 1;\n\n    # Then run the perl debugger to navigate there quickly:\n    PERLDBOPT='Nonstop' perl -d my_script\n\nIf that works for you, then dont' bother with this module!\n(joke. still try it.)\n\n### Devel::REPL\n\nThis is a great and extendable module!\n\nUnfortunately, I did not find a way to get the lexical variables\nin a scope. (maybe I missed a plugin?!)\n\nExample:\n\n    perl -MDevel::REPL -E '\n        my  $my_var  = 111;                # I want to access this\n        our $our_var = 222;                # and this.\n        my $repl = Devel::REPL-\u003enew;\n        $repl-\u003eload_plugin($_) for qw(\n            History\n            LexEnv\n            DDS\n            Colors\n            Completion\n            CompletionDriver::INC\n            CompletionDriver::LexEnv\n            CompletionDriver::Keywords\n            CompletionDriver::Methods\n        );\n        $repl-\u003erun;\n    '\n\nSample Output:\n\n    $ print $my_var\n    Compile error: Global symbol \"$my_var\" requires explicit package name ...\n\n    $ print $our_var\n    Compile error: Global symbol \"$our_var\" requires explicit package name ...\n\n### Reply\n\nThis module also looked nice, but same issue.\n\nExample:\n\n    perl -MReply -E '\n        my $var=111;\n        Reply-\u003enew-\u003erun;\n    '\n\nSample Output:\n\n    \u003e print $var\n    1\n    \u003e my $var2 = 222\n    222\n    \u003e print $var2\n    1\n\n## This Module\n\nWhile debugging some long-running, perl,\nSelenium test files, I basically got bored\nduring the long waits, and created a simple\nRead Evaluate Print Loop (REPL) to avoid\nthe annoyong waits between test tries.\n\nOriginally I would have a hot key\ncommand to drop in a snippet of code like\nthis into my test code to essentially insert\na breakpoint/pause.\n\nOne can then examine what's going on in that\narea of code.\n\nOriginally the repl code snippet was something\nas simple as this:\n\n    while(1){\n      my $in = \u003cSTDIN\u003e;\n      chomp $in;\n      last if $in eq 'q';\n      eval $in;\n    }\n\nWith that small snippet I could pause in a long\nrunning test (which I didn't write) and try out\ncommands to help me to understand what needs to\nbe updated in the test (like a -\u003eclick into a\nfield before text could be entered).\n\nAnd I was quite satisfied.\n\nFrom there, this module increased in features\nsuch as using `Term::ReadLine` for readline\nsupport,tab completion, and history (up arrow).\n\n### Attempts\n\nThis module has changed in its approach quite a\nfew times since it turns out to be quite tricky\nto perform `eval_in_scope`.\n\n#### Source Filter\n\nTo make usage of this module as simple as\npossible, I tried my hand at source filters.\n\nMy idea was that by simply adding this line\nof code:\n\n    use Runtime::Debugger;\n\nThat would use a source filter to add in the REPL code.\n\nThis solution was great, but source filters can only\nbe applied at COMPILE TIME (That was new to me as well).\n\nUnfortunately, the tests I am dealing with are\nread as a string then evaled.\n\nSo, source filters, despite how clean they would\nmake my solution, would not work for my use cases.\n\nNext idea.\n\n#### Back To Eval\n\nThen I decided to go back to using a command like:\n\n    use Runtime::Debugger;\n    eval run;\n\nWhere run would basically generates the REPL\ncode and eval would use the current scope to\napply the code.\n\nSide note: other Debuggers I had tried before this\none, do not update lexical variables in the\ncurrent scope. So this, I think, is unique in this debugger.\n\n#### Next pitfall\n\nI learned later that `eval run` would under\ncertain circumstances not work:\n\nFirst call would print 111, while the exact\nsame eval line would print undef afterwards.\n\n    sub {\n        my $v = 111;\n        eval q(\n            # my $v = $v; # Kind of a fix.\n            eval 'say $v'; # 111\n            eval 'say $v'; # undef\n        );\n    }-\u003e();\n\n#### Still can eval run\n\nUsing `eval run` is still possible (for now).\n\nJust be aware that it does not evaluate correctly\nunder certain circumstances.\n\n## Solution\n\nSimply add these lines:\n\n    use Runtime::Debugger;\n    repl;\n\nThis will basically insert a read, evaluate,\nprint loop (REPL).\n\nThis should work for more cases (just try not\nto use nasty perl magic).\n\n### Goal\n\nTo reach the current solution, it was essential\nto go back to the main goal.\n\nAnd the goal/idea is simple, be able to evaluate\nan expression in a specific scope/context.\n\nBasically looking for something like:\n\n    peek_my(SCOPE)\n\nBut instead for eval:\n\n    eval_in_scope(SCOPE)\n\nGiven `eval_in_scope(1)`, that would evaluate an expression,\nbut in a scope/context one level higher.\n\n### Implementation\n\n#### Scope\n\nIn order to eval a string of perl code correctly,\nwe need to figure out at which level the variable\nis located.\n\nThats not hard to do: just look through increasing\n`caller()` levels until finding the first whose\npackage name is not thia module's.\n\n#### Peek\n\nGiven the scope level, peek\\_my/our is utilized\nto grab all the variables in that scope.\n\nHaving these variables:\n\n    my  $var = 111;\n    our $var = 222;\n\nThere can only be a single variable (glob) of\na name. When multiple, the lexical one would\nbe used.\n\n#### Preprocess\n\nThen we need to preprocess the piece of perl code\nthat would be evaled.\n\nAt this stage variables would be replaced which\ntheir equivalent representation at found in\npeek\\_my/our.\n\nThis code:\n\n    say $var\n\nMight be replaced with something like this:\n\n    say ${$PEEKS{'$var'}}\n\nThis transformation would normally be done\nseamlessly and hidden from the user.\n\n#### Eval\n\nFinally, eval the string.\n\nAnd we pretend to have done `eval_in_scope`.\n\n### Future Ideas\n\nOne idea would be to create an XS function\nwhich can perform an eval in a specific scope,\nbut without the translation magic that is\ncurrently being done.\n\nThis might appear like peek\\_my, but for eval.\nSo something like this:\n\n    eval_in_scope(\"STRING_TO_EVAL\", SCOPE_LEVEL);\n\n# FUNCTIONS\n\n## run\n\nDEPRECATED! (Use `repl` instead)\n\nRuns the REPL.\n\n    eval run\n\nSets `$@` to the exit reason like\n'INT' (Control-C) or 'q' (Normal exit/quit).\n\nNote: This method is more stable than repl(), but at the same\ntime has limits. [See also](#lossy-undef-variable)\n\n## repl\n\nWorks like eval, but without [the lossy bug](#lossy-undef-variable)\n\n    repl (\n        history_file =\u003e \"$ENV{HOME}/.runtime_debugger.yml\",\n        debug        =\u003e $ENV{RUNTIME_DEBUGGER_DEBUG} // 0,\n        levels_up    =\u003e 0,\n    );\n\nCan specify the level at which to perform an eval\nin relation to the level of this function call:\n\n    levels_up =\u003e 0,  # Default\n    levels_up =\u003e 1,  # One scope/level above this.\n                     # Useful for scripts using this.\n    levels_up =\u003e -1, # One level below for internals.\n\n## \\_apply\\_peeks\n\nTransform variables in a code string\ninto references to the same variable\nas found with peek\\_my/our.\n\nTry to insert the peek\\_my/our references\n(peeks) only when needed (should appear\nnatural to the user).\n\nOk to transform:\n\n    say \"@a\"\n\nNOT ok to transform:\n\n    say \"%h\"\n\n## Tab Completion\n\nThis module has rich, DWIM tab completion support:\n\n    Press TAB when:\n\n    - No input - view commands and variables.\n\n    - After arrow (\"-\u003e\") - to auto append either a \"{\" or \"[\" or \"(\".\n      (Depends on variable type)\n\n    - After a hash) - show keys.\n\n    - Otherwise - show variables.\n\n## \\_match\n\nWrapper to simplify completion function.\n\nInput:\n\n    words   =\u003e ARRAYREF, # What to look for.\n    partial =\u003e STRING,   # Default: \"\"  - What you typed so far.\n    prepend =\u003e \"STRING\", # Default: \"\"  - prepend to each possiblity.\n    nospace =\u003e 0,        # Default: \"0\" - will not append a space after a completion.\n\nReturns the possible matches:\n\n## help\n\nShow help section.\n\n## History\n\nAll commands run in the debugger are saved locally and loaded next time the module is loaded.\n\n## hist\n\nCan use hist to show a history of commands.\n\nBy default will show 20 commands:\n\n    hist\n\nSame thing:\n\n    hist 20\n\nCan show more:\n\n    hist 50\n\n## d\n\nData::Dumper::Dump anything.\n\nYou can use \"d\" as a print command which\ncan show a simple or complex data structure.\n\n    d 123\n    d [1, 2, 3]\n\n## dd\n\nDevel::Peek::Dump.\n\nYou can use \"dd\" to see the inner contents\nof a structure/variable.\n\n    dd @var\n    dd [1..3]\n\n## p\n\nData::Printer::p\n\nYou can use \"p\" as a print command which\ncan show a simple or complex data structure\nwith colors.\n\nSome example uses:\n\n    p 123\n    p [1, 2, 3]\n    p $scalar\n    p \\@array\n    p \\%hash\n    p $object\n\n## uniq\n\nReturns a unique list of elements.\n\nList::Util in lower than v5.26 does not\nprovide a unique function.\n\n## Internal Properties\n\n### attr\n\nInternal use.\n\n### debug\n\nInternal use.\n\n### levels\\_up\n\nInternal use.\n\n### term\n\nInternal use.\n\n# ENVIRONMENT\n\nInstall required library:\n\n    sudo apt install libreadline-dev\n\nEnable this environmental variable to\nshow debugging information:\n\n    RUNTIME_DEBUGGER_DEBUG=1\n\n# SEE ALSO\n\n## [https://perldoc.perl.org/perldebug](https://perldoc.perl.org/perldebug)\n\n[Why not perl debugger?](#perl5db-pl)\n\n## [https://metacpan.org/pod/Devel::REPL](https://metacpan.org/pod/Devel::REPL)\n\n[Why not Devel::REPL?](#devel-repl)\n\n## [https://metacpan.org/pod/Reply](https://metacpan.org/pod/Reply)\n\n[Why not Reply?](#reply)\n\n# AUTHOR\n\nTim Potapov, `\u003ctim.potapov[AT]gmail.com\u003e` 🐪🥷\n\n# BUGS\n\n## Control-C\n\nDoing a Control-C may occassionally break\nthe output in your terminal (exit with 'q'\nwhen possible).\n\nSimply run any one of these:\n\n    reset\n    tset\n    stty echo\n\n## New Variables\n\nCurrently it is not possible to create new\nlexicals (my) variables.\n\nYou can create new global variables by:\n\n    - Default\n      $var=123\n\n    - Using our\n      $our $var=123\n\n    - Given the full path\n      $My::var = 123\n\n## Lossy undef Variable\n\ninside a long running (and perhaps complicated)\nscript, a variable may become undef.\n\nThis piece of code demonstrates the problem\nwith using c\u0026lt;eval run\u003e.\n\n    sub Func {\n        my ($code) = @_;\n        $code-\u003e();\n    }\n\n    Func( sub{\n        my $v2 = 222;\n\n        # This causes issues.\n        use Runtime::Debugger;\n        eval run;\n\n        # Whereas, this one works.\n        use Runtime::Debugger;\n        repl;\n    });\n\nThis issue is described here [https://www.perlmonks.org/?node\\_id=11158351](https://www.perlmonks.org/?node_id=11158351)\n\n## Other\n\nPlease report any (other) bugs or feature\nrequests to [https://github.com/poti1/runtime-debugger/issues](https://github.com/poti1/runtime-debugger/issues).\n\n# SUPPORT\n\nYou can find documentation for this module\nwith the perldoc command.\n\n    perldoc Runtime::Debugger\n\nYou can also look for information at:\n\n[https://metacpan.org/pod/Runtime::Debugger](https://metacpan.org/pod/Runtime::Debugger)\n\n[https://github.com/poti1/runtime-debugger](https://github.com/poti1/runtime-debugger)\n\n# LICENSE AND COPYRIGHT\n\nThis software is Copyright (c) 2022 by Tim Potapov.\n\nThis is free software, licensed under:\n\n    The Artistic License 2.0 (GPL Compatible)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoti1%2Fruntime-debugger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpoti1%2Fruntime-debugger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoti1%2Fruntime-debugger/lists"}