Fork me on GitHub
#off-topic
<
2024-07-06
>
ericdallo20:07:05

There is a regex (`.*>\s+([^>]+)$`) that should catch what the user wanna eval, but it's missing some cases like in the print: Test strings:

user> foo
foo> 12
foo> asdasd
asd
asdas?

asd
foo>     123123
foo>   sdsd->asd
fga> (tap> 232)
foo> 123*&$#!?<+-
foo> (bar [1 2 3])
https://regex101.com/

ericdallo20:07:46

the hard part is to match a code with \n too, but the issue bug is that we are not matching > , (because of the [^>]), my idea is that I want to match anything until the next \n.*> or all if there is none.

lread20:07:56

I'm guessing you absolutely need to use a regex?

lread21:07:00

But... if you like a puzzle... maybe this would work?: (?m)(^\w+>\s*)([\s\S]*?)(?=\n^\w+>\s*|\z)

ericdallo21:07:23

Yeah, I definitely would prefer avoid the regex, but the way clojure-repl-intellij works ATM, we don't have much choice, we only have a raw text of the reply content

ericdallo21:07:41

Humm, I'll try that one!

lread21:07:46

That's Java pattern syntax, I assume that is the regex flavour you are using.

lread21:07:03

Oh it's clojure code, cool then.

lread21:07:50

I tested the above over at http://regex101.com against your sample input. Seems to work, at least there! simple_smile

ericdallo21:07:54

yes, it works on the regex101! thank you for some reason in the clojure it works differently :thinking_face: I mean, for this case, it should return the last foo only (the code that needs to be evaluated)

lread21:07:22

Does your sample need to include the ;; => lines?

ericdallo21:07:48

Yeah, since it's the whole repl content 😔

ericdallo21:07:08

it's weird that it works on regex101 tho:

lread21:07:41

I can fire up a REPL to see what I see. Can you paste your updated sample text?

lread21:07:35

For your original sample I'm finding it works, I think. I'm really not sure exactly what you need. But:

(def sample (slurp "sample.txt"))

(def matcher (re-matcher #"(?m)(^\w+>\s*)([\s\S]*?)(?=\n^\w+>\s*|\z)" sample))

(re-find matcher)
;; => ["user> foo" "user> " "foo"]

(re-find matcher)
;; => ["foo> 12" "foo> " "12"]

(re-find matcher)
;; => ["foo> asdasd\nasd\nasdas?\n\nasd" "foo> " "asdasd\nasd\nasdas?\n\nasd"]

(re-find matcher)
;; => ["foo>     123123" "foo>     " "123123"]

(re-find matcher)
;; => ["foo>   sdsd->asd" "foo>   " "sdsd->asd"]

(re-find matcher)
;; => ["fga> (tap> 232)" "fga> " "(tap> 232)"]

(re-find matcher)
;; => ["foo> 123*&$#!?<+-" "foo> " "123*&$#!?<+-"]

(re-find matcher)
;; => ["foo> (bar [1 2 3])\n" "foo> " "(bar [1 2 3])\n"]

(re-find matcher)
;; => nil

ericdallo21:07:25

Interesting, I think it's a corner case with repl results ;; => 1 this is the sample I'm using:

";; some text here
user> 1
;; => 1
user> foo" 
using that regex, the last group returned is: "i\n;; => 1" but it should be foo

lread21:07:19

Here's my results for your new sample (which I plunked in a file):

(re-find matcher)
;; => ["user> 1\n;; => 1" "user> " "1\n;; => 1"]

(re-find matcher)
;; => ["user> foo\n" "user> " "foo\n"]

(re-find matcher)
;; => nil
Did you want to match the ;; lines differently somehow?

ericdallo23:07:05

ah got it, TBH I didn't know re-find and re-matcher behave that different, so yeah, I'd want the second result of (re-find matcher) , is tere any way to get that using re-find ? Otherwise I don't know how I can use it like you showed because I'd need to always get the last result that is not nil I suppose

lread01:07:37

Oh, so you are looking to find the last prompt and entry only?

lread01:07:08

And you can't iterate over over a matcher with re-find?

lread02:07:51

Without understanding the constraints you are up against, could you use re-seq like so? (I have your 2nd sample in sample2.txt)

(->> "sample2.txt"
     slurp
     (re-seq #"(?m)(^\w+>\s*)([\s\S]*?)(?=\n^\w+>\s*|\z)")
     last)
;; => ["user> foo\n" "user> " "foo\n"]

lread02:07:53

Actually, this regex is complicated enough to merit comments (note the x in (?mx) ):

(->> "sample2.txt"
     slurp
     (re-seq #"(?mx)             # match multiline and allow comments
               (^\w+>\s*)        # group1: match the prompt
               ([\s\S]*?)        # group2: match entry
                                 # - we use [\s\S] instead of . because . does not match newlines
               (?=\n^\w+>\s*|\z) # lookahead for next prompt or end of string")
     last)
;; => ["user> foo\n" "user> " "foo\n"]

lread02:07:56

If I come to understand what you are really trying to extract, we can probably simplify

ericdallo17:07:31

sorry for the delay, and thanks for the help so far! Let me explain how the feature works, we have https://github.com/afucher/clojure-repl-intellij plugin which is basically cider for intellij, so we have a REPL output where the user can see and interact with a repl (print1). https://github.com/afucher/clojure-repl-intellij/blob/b4a3d089cb19629fbc9460c4ff69d07a31e31619/src/main/clojure/com/github/clojure_repl/intellij/ui/repl.clj#L79 that builds that REPL is basically some seesaw which is java swing under the hood. The way it works ATM is that is a fancy JTextField, and when user inputs the code that wants to evaluate we need to know that code, but since it's a JTextField all the previous written and outputed content will be there, so we use a regex to extract the code user wants to send to repl, I know it's not pretty, but I tried to create a cider similar xp, than have a output window and a input one, does that makes sense?

ericdallo17:07:01

BTW your re-seq seems to work, but I'll test other cases hehe 👀

ericdallo17:07:43

I didn't even know you could comment regex like that 😯, that's so useful

lread17:07:55

Oh cool! As an old colleague and I used to joke sometimes, "A job all done!" (instead of "A job well done!")

😅 1
lread17:07:41

Yeah the comment feature is great because regexes are do dense and confusing!

ericdallo17:07:11

yeah, I with we didn't need the regex, as "If you solve a problem with regex, now you have 2 problems" 😂

simple_smile 1
lread17:07:14

There is also https://github.com/lambdaisland/regal which provides a different way to doc regexes.

ericdallo17:07:00

oh yeah, I heard about but never tried TBH, maybe a good oportunity

lread17:07:54

I've not tried it yet either, but might someday!

ericdallo17:07:46

hehe found a corner case with - : for ns with - or . on its name

(extract-code-to-eval ";; some text here
user> 1
;; => 1
user-bar.a> foo")

=> "1\n;; => 1\nuser-bar.a> foo"

ericdallo17:07:31

manage to fix it with this regex:

#"(?mx)             # match multiline and allow comments
    (^.+>\s*)        # group1: match the prompt
    ([\s\S]*?)        # group2: match entry
                      # - we use [\s\S] instead of . because . does not match newlines
    (?=\n^.+>\s*|\z) # lookahead for next prompt or end of string"
not sure I'll break other cases

ericdallo17:07:39

(replaced the \w with .)

ericdallo17:07:15

although would be safer to check for - and . as I don't think namespaces can have other crazy chars

lread17:07:43

Ah but that might interpret ;; => as a prompt? You ok with that?

ericdallo17:07:05

also that breaks the original issue:

(extract-code-to-eval ";; some text here
user> 1
;; => 1
user> (tap> 1)")
as we want to fix the usage of functions with > on their name

ericdallo17:07:29

that seems to fix for ns with - but not with . :thinking_face:

#"(?mx)                    # match multiline and allow comments
    (^[\w|-|\.]+>\s*)        # group1: match the prompt
    ([\s\S]*?)               # group2: match entry
                             # - we use [\s\S] instead of . because . does not match newlines
    (?=\n^[\w|-|\.]+>\s*|\z) # lookahead for next prompt or end of string"

lread17:07:12

You character class looks off. Just list the chars, no need for the | bars or the escapes \, so maybe [\w.-]

ericdallo17:07:40

hum, didn't know that

ericdallo17:07:48

seems to work! doing more tests..

ericdallo17:07:02

that deserve some dedicated unit tests hehe

lread17:07:54

For sure!

ericdallo18:07:33

ok, new corner case, but seems it's almost there

(defn code [& strings]
  (string/join "\n" strings))

(deftest foo
  (is (= (code  "(defn foo []"
                "  (tap> 123)"
                "  123)")
         (#'ui.repl/extract-code-to-eval (code ";; some text here"
                                               "user-bar.baz> 1"
                                               ";; => 1"
                                               "user-bar.baz> (defn foo []"
                                               "                (tap> 123)"
                                               "                123)")))))

ericdallo18:07:53

the case is: a code with new lines and functions with > in the name :melting_face:

ericdallo18:07:33

hum, actually it's related with the ns name as well, because changing from user-bar.baz to user works

ericdallo18:07:22

never mind, it was a missing ) I guess

ericdallo18:07:54

I think I covered all discussed cases, enough to solve the issue, I'll create more unit tests later thank you so much for the help @UE21H2HHD! will co-author you if you don't mind but need your github email

lread18:07:01

You are most welcome, no need for any co-authoring, it's all good!

💙 1
lread18:07:55

I'm gonna guess you'll uncover more edge cases! simple_smile If you don't absolutely have to use regexes, you might consider something like https://github.com/Engelberg/instaparse. Or just parse line by line if you can. I think that would be easier.

ericdallo18:07:04

yeah, I thought about parsing each line but sounded harder, but it probably worth the try

teodorlu22:07:13

I'm starting to think that we should just create drastically less stuff. Perhaps I'm late to the party. But. Write less code. Move slower. Actually know what we're doing. Not try to make anyone work as fast as they can, rather give and encourage slack.

💯 14
lread22:07:04

You must have been influenced by the Clojure core team! simple_smile

😄 6
teodorlu22:07:24

Nothing new under the sun! 😄

Bob B23:07:00

There was a Dan North talk where he said something like "the goal of the software industry isn't to produce software, it's to solve problems... if you can solve problems without creating software, you win at software"

metal 2
seancorfield06:07:14

I was going over my OSS projects today and seeing what "needed" doing and in the end I just did some editorial stuff on http://clojure-doc.org -- the rest was either "not needed" or "I haven't figured out a good solution" so I'd rather not add code unless I really have a purely additive and fairly minimal change.

👍 3
didibus07:07:45

I've been thinking about this lately as well. At work, it tends to be that there's a project, with a deadline, and you work towards it. And it seems the solution to make those deadlines has become brute force and sheer will power. Some kinds of: work longer, work harder, hire more people, get some contractors, pull people off from other less important projects, etc. And this has been going for a long time. But it creates a result where the next one you need to work even more hard, more long, bring in even more people, or accept that the deadline won't happen. And I can't help but feel like, you don't need that many people, you don't need to work hard and long. You need to be smarter. When you make a change, it's got to be impactful, and well thought through, keep things simple, decomplected and won't mess up with the integrity of the system. And you need to work on having good teams, that know what they are doing. In my opinion, good teams that know what they are doing and allowing for changes to be well thought out, actually results in a much higher velocity and ending up delivering a lot more quickly and with way better results. My conclusion is it's really hard from a management/hiring point of view to build good teams like that, and trust them that them "taking their time" will in fact make projects launch faster and better.

stas08:07:05

Agree. Not creating Node.js would be a benefit to humanity.

😆 1
Ben Sless08:07:27

I remember this picture going around bashing open floorplans then the creator of react commented they would have never been able to create react in any other environment Sort of making the point there, bud

🙂 1
jumar15:07:32

But you know: moving slower is not “agile”

😄 1
Ben Sless15:07:41

> slow is smooth, smooth is fast

☝️ 1
Bob B15:07:08

I would argue that making breaking API changes every 20 minutes isn't "agile" either, but it all comes down to how people view "agile". It can be a case of "just 2 days of bugfixes and deployments and mad customers saved us 2 hours of design conversation". This sort of reminds me of the hammock-driven development talk - it's faster to fix the bugs in design, so it's often not slower, but it can appear slower if the metric of speed is counting deployments or stories (without noting how many of those deployments/stories are re-work).

lemuel19:07:42

Being ‘agile’ is commonly used as an excuse for having no plan. Facebook ended up dropping ‘move fast and break things.’ Maybe because they had a terrible codebase or they broke democracy

didibus19:07:45

I feel actually there's a version of move fast and break things that is more like about not hesitating to make ambitious changes and refactoring. The alternative sometimes is people actually prefer to hack, as it might involve needing less major refactoring or changes, and they do that as they worry they might "break" things. When in my opinion the refactor is needed. And this is where an effective team has everything needed for this as well, a good test suite, and continuous integration that they trust. So they don't have to worry about "breaking" things, and still can feel like they can take ambitious refactors when needed.

didibus19:07:38

You can see it a lot (especially in OOP), with like, refactoring the inheritance chain, or object structure seems too risky, so you just start to put more and more logic in existing classes, breaking SOLID, etc.