backslashes and double-quotes in text input widgets

Preface: Please do not read this as part of another endless series of lamentations, I already have solutions for all these things on store, but would first like to ask here in the forum before I send patches to the Audacity developers list. Only to prevent misunderstandings, I’m talking about the text input widget of the Audacity Nyquist user interface that appears if a Nyquist plugin header contains a line like:

;control <variable-name> "text-left" string "text-right" "initial-string"

Known problems with the current implementation of the Adacity text input widget:

Single backslashes will not be doubled, so the Audacity user [who is usually not a Lisp programmer] has to type double-backslashes in the input field of the text widget in the Audacity Nyquist interface or will inadvertibly run into trouble:

Audacity text widget      Lisp string
c:\programs\audacity => "c:\programs\audacity"       ; works but needs double-backslashes
c:programsaudacity   => "c:programsaudacity"         ; bad
c:programsaudacity  => error: unexpected end of file  ; even worse :(

Double-quotes are converted to single-quotes by the Audacity Nyquist interface, what is a pretty idiotic idea, because the Lisp single-quote read-macro serves the purpose to prevent evaluation:

Audacity text widget     Lisp string
"hello"              => "'hello'"     ; what a nonsense

Suggested solutions:

With my Audacity 1.3.13-alpha version at home I have modified the C/C++ code of the Audacity Nyquist interface.

Backslashes now automatically get doubled and double-quotes automatically get quoted:

Audacity text widget      Lisp string
c:programsaudacity  => "c:\programs\audacity"    ; backslashes automatically get doubled
c:programsaudacity => "c:\programs\audacity\"  ; backslashes do not cause Lisp errors anymore
"hello"               => ""hello""                 ; double-quotes are quoted and retained, so the
non"sense"example     => "non"sense"example"       ; Lisp string reflects the original user input

The modification of the C/C++ code is pretty simple. In case you want to try it yourself, here is what I did.

In the file “src/effects/Nyquist.cpp” in the function “EffectNyquist::ProcessOne()”, around line 650, you’ll find the following code fragment:

      else if (mControls[j].type == NYQ_CTRL_STRING) {
         wxString str = mControls[j].valStr;
         str.Replace(wxT("""), wxT("'"));   // <- replace this line with the two lines below
         cmd += wxString::Format(wxT("(setf %s "%s")n"),
                                 mControls[j].var.c_str(),
                                 str.c_str());
      }

Here is the modified version:

      else if (mControls[j].type == NYQ_CTRL_STRING) {
         wxString str = mControls[j].valStr;
         str.Replace(wxT("\"), wxT("\\"));  // <- double all backslashes
         str.Replace(wxT("""), wxT("\""));  // <- quote all double-quotes
         cmd += wxString::Format(wxT("(setf %s "%s")n"),
                                 mControls[j].var.c_str(),
                                 str.c_str());
      }

The remaining question is: Are there more problems known or do I have forgotten something?

Thanks - edgar

My initial response is that these sound like excellent enhancements.
There are no immediate problems that come to mind, and I doubt that it will break any of the existing plug-ins that are in general circulation.

Have you tried it with the "Nyquist Generate Prompt "? I expect it will remove several of the limitations in this plug-in.

Are there any issues regarding the following characters (and character combinations) that need to be considered?

; (semicolon)
#| (hash pipe)
|# (pipe hash)
(backslash)
#’ (hash quote)

Thanks for the tests (I hadn’t tried them all before), here are the results with the modified Audacity Nyquist text input widget:

;  (semicolon)  => ";"
#| (hash pipe)  => "#|"
|# (pipe hash)  => "|#"
  (backslash)  => "\"  <- this started my investigations
#' (hash quote) => "#'"

With the Nyquist “Generate prompt” plugin I get the following results:

;; (print #| invisible |# (funcall #'+ 1 2 3)) ; comment

Line 1: (print
Line 2: #| invisible
Line 3: |# (funcall
Line 4: #'+ 1 2 3))
Line 5: ; comment

=> 6

Are there more tests cases known? - edgar

That’s excellent - it makes a big improvement to the Nyquist Generate Prompt.
I’m building Audacity with your modification at the moment - I’ll let you know if I hit any issues when I start testing.

At the risk of rubbing salt into old wounds, I presume this does not have any adverse effect on commas as decimal separators in European locales?

Theoretically this has [luckily :slight_smile: ] nothing to do with each other, but practice teaches that everything ist possible. I do not think that my changes affect the dot-vs-comma issue with floating point numbers, but you’re right, it’s better to test everything possible.

I’m just trying to understang [for the approx. hundredst time] how the Audacity Nyquist interface works, so hopefully I can fix this myself in the future. But do not promise yourself to much, because I’m a really, really bad C/C++ programmer. :frowning:

Over the weekend I tried to write a Nyquist textfile-io library and I couldn’t even type a Windows filename into the text input widget without producing endless Lisp errors. That’s why I started to investigate the C/C++ code.

I’ve just sent the patch to the Audacity devel-list, so maybe the backslash and double-quote issues will be fixed in the future.

More about text files in the next few days … - edgar

I’ve got it built now and done some testing - not found any problems so far, it looks very good.
With this improvement I thought it worth updating the Nyquist Generate Prompt so that it will support multiple expressions (it didn’t seem worth the effort previously because of the other limitations that you have now fixed). https://forum.audacityteam.org/t/nyquist-wish-list-nyquist-prompt-enhancement/16379/6