Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser: Multiline strings #1648

Closed
wants to merge 1 commit into from

Conversation

tenbits
Copy link

@tenbits tenbits commented Nov 8, 2013

Added multiline string feature to the parser:
''' long_multiline_string '''
""" long_multiline_string """

.keyframes(~'''
    foo,
    from { opacity: 0 }
    to { opacity: 1 }
''');

As you see from the example above, this is especially useful for the mixin arguments.

In case you have other ideas regarding syntax, etc, I'm eager to change this pull request.

Things to consider:

  • should the new lines and the trailing white-spaces be removed from the string?

What do you think about this pr?

Cheers, Alex

@marekhrabe
Copy link

this would be so awesome! 👍

@petrbrzek
Copy link

👍

1 similar comment
@thomasboyt
Copy link

👍

@seven-phases-max
Copy link
Member

I did not want to express my opinion on this feature since I probably am a greatest adversary of the ~"" overuse. But here're just a few thoughts on the proposed syntax without carping the feature as a whole:

A. So if we consider multiline escaped strings to be a valueable addition to the LESS why should it be another syntax? ~"""Really?""". We can simply allow multiline ~"" (Pros: clean look. Cons: it will screw LESS syntax highlighting in most of editors, as ~"""""" will though).
B. Obviously, all use-cases where ~"""""" are helpful use these escaped strings as macros (yes, just plain old-school text-replace macros just like in preprocessors of 70's, e.g. C-preprocessor or m4). So if (multiline) macros become an unavoidable feature in the LESS why we should shyly hide it behind those ~"" and ~"""""" euphemisms? So if we need macros should not it be just macro (or define or whatever syntax we'll find suitable)?. Pros: non-misleading and legible syntax. Cons: new keyword/directive.

P.S. Just in case, personally I'd prefer such .keyframes puzzles (and similar use-cases) to be solved via #965 (i.e. using mixins, not macros and inline javascript).

@lukeapage
Copy link
Member

@seven-phases-max I fully agree

The only downside I can see in just allowing multiline strings is that you are less likely to catch errors where someone misses off the closing quote.

I'm trying to think why most languages ban it and I can only come up with ambiguity over whether it is \n or \r\n etc. and that you don't usually want re-formatting a code file to windows or unix to effect the string constants.

@tenbits
Copy link
Author

tenbits commented Dec 13, 2013

OK, some more points of mine. But please interpret this only as a friendly discussion )

From the clash of opinions emerges the truth

Multi-line literals are present in many good languages - C#, Python, Scala, Groovy. Only in C# is used @"" syntax (something similar to ~"" suggested by @seven-phases-max), but triple quotes are definitely better, as also any other quotes inside of the literal can be used without escaping it - and this is valuable thing, equivalent to the 'multilines' itself. So I would call this feature not a multi-line literals, but the 'block literals' - anything can be used in there (except triple quotes)). Additionally block boundaries are better and cleaner to describe with triple quotes instead of a single ones. So if when to use or implement block literals, then only with the triple quotes. In less-alike html template engine - MaskJS, I also use triple quotes feature, even though new lines can be used in generic literals - only for the ability to write some html, json etc. inside of it without the need to escape the quotes. So when you decide to use some other syntax, like proposed macro( - you force people to escape all end parentheses inside of the macro ()) - and it is not much fun to do this.

We also face no problems with the CRLF/LF. Actually we do nothing about it - as browsers manage this well by itself, and if a consumer of the literal needs to handle it, it is free to do this.
That's why I think block literals are always better with the triple quotes.

Other side - do Less preprocessor needs block literals? I came across the lack of it in keyframes declarations - nowadays keyframe animation is a usual thing, and as for now in less there is no good ways to declare them. Or do I miss something? @seven-phases-max, mixins can be good solution for this also, but when they will be availabe in Less? Will it handle also nested mixins inside keyframe step declaration?
Guys from lesshat created very useful and easy to use mixins to handle all cross-browser stuff, nice transformation mixins, but they came not so good with the keyframes - everything is done: cross-browser keyframe declaration, nested mixins support, but the limitation - only one-line declaration. @petrbrzek can may be say more about what they tried and what desired features they would like to see. I personally have nothing to do with that team. I am a person, who wants Less.js & Co to be effectively usable and also good extendable. That's why I think javascript feature and literal block feature will allow some other add-ons or mixins to implement any imaginable behaviour.

  • Cheers

@seven-phases-max
Copy link
Member

you force people to escape all end parentheses inside of the macro ()

You don't need to escape any parentheses inside whatever () (or whatever {}, or even macro ... endmacro :) as soon as number of opening and closing parens match. (Just like we do this with all of those nesting LESS rulesets).

Guys from lesshat created very useful and easy to use mixins to handle all cross-browser stuff,

Well, yes, lesshat will benefit from these 'block literals' (more over, only lesshat will benefit from it - notice that you can't extract foo w/o javascript hacks within your keyframes example). That's actually why I did not want to express my opinion on the approach as a whole, now I have to be a bad guy and say this: with all respect to lesshat, do I really need to bloat my less code with "crossbrowser mixins" when I can simply write just plain standard css stuff and let a tool(s) like autoprefixer do the rest of cross-browser trickery for me?

But yet again, I do not agitate against this proposal, I just concern about chosen syntax. Six quotes leaded by tilde...

mixins can be good solution for this also, but when they will be availabe in Less?

Sorry but I don't think also is applicable in this case. With all respect (yet again) to lesshat:

.keyframes(~'animationName, 0%{ transform: scale(1.5); color; blue } 100%{ transform: scale(2), color: red }');

How soon I will find this animation does not work properly with my page and how soon I will find why exactly it does not work? I.e. these solutions are barely comparable.

@tenbits
Copy link
Author

tenbits commented Dec 13, 2013

Max, it is OK, all clever people understand what a good desput is, and that nobody is a bad guy in it )

whatever()

You are right until there is a strict - (tree structured) - macro/block syntax inside. And when we assume, that the argument is handled by the `javascript hacks', then the restriction on a syntax could prevent from some good transformations.

Autoprefixer is great, but I prefer e.g .scale(1.5) instead of plain css transform: scale(1.5), and if a mixin also handles cross-browser prefixes - this is nice, as then there is one less toolchain in an application building process.

Using 'block literals' and 'javascript hacks' is surely more error prone approach then an official LESS parser, but it allows to create things, that with LESS are not possible. You can think about this technic as a low level integration into LESS Core. With it some new ideas, features, other syntax and stuff can be implemented as experimental or production ready feature. May be some widget based library can use this 'low level integration' ... brief ideas:

.wdgt-carousel(~'''
    background: red
    images:
        - 'img-1).png'
        - 'img-2).png'
    # some other settings
''');

You see, I used yaml syntax as an argument for the widget. And the widget itself contains of some LESS 'javascript hack' addon (that parses the arguments and generates css), and the plain javascript that generates html and handles interactivity.

Your last statement is applicable to the whole javascript. Many people say - "No strict types? Really? How soon I will find an error, when something goes wrong" :)

Max, but in general you are also right, so any decision upon this proposal, even negative, will not make LESS less great :)

@seven-phases-max
Copy link
Member

To be honest, both my examples were a bit unfair, the foo one can be written like this:

.keyframes(
    foo, ~'''
    from { opacity: 0 }
    to { opacity: 1 }
''');

And the typo example ignores the fact that I'll get exactly the same problem with just plain CSS misprints, e.g.:

@keyframes foo {0% {transform: scale(1.5); colour: blue} 100% {tranzform: scale(2); color: red}}

@Soviut
Copy link

Soviut commented Dec 13, 2013

@tenbits The benefits of autoprefixer aren't just that it applies prefixes, but that it only applies the necessary prefixes. Even if you're using mixins that generate prefixes, you should still be running the resulting CSS through autoprefixer to eliminate all the unnecessary prefixes that are inevitably generated.

@jonschlinkert
Copy link
Contributor

It’s a perfect example of bad design and improper decisions

You're comment is a perfect example of someone who made no attempt to assist in those decisions at the time, or has made no attempt to contribute the solutions you're creating back to the community - for commercial or other reasons, it doesn't matter.

So @petrbrzek what are you planning to contribute to this community help less.js achieve the things your company needs?

@seven-phases-max
Copy link
Member

you have to create: ...

Only if you use Less as a wrapper for a JavaScript autoprefixing library like the one mentioned here.
(Well, I guess I have already expressed my opinion somewhere in other issues. If my library had thousands lines of JavaScript code to generate 100 lines of Less code I would really wonder what's that Less thing is doing there at all and why can't I simply generate CSS directly with JavaScript (be it a browser script or a node tool)).

@matthew-dean
Copy link
Member

Honestly, I don’t like LESS architecture. It’s a perfect example of bad design and improper decisions [so, I decided to invest my time in building a library on top of this thing that I dislike, and then tell you guys about it.]

Um...

@petrbrzek I don't agree with all of Less's design decisions either, but that's why I spend my time giving input into it's future growth, which, as @jonschlinkert said, is probably a bit more constructive. If you think Less Hat "solves" architecture issues in Less, why not a) open an issue describing your real-world problem(s), b) propose solutions.

For the record, I've been looking at Lesshat specifically. One of my goals is to help remove any need for Less.js to ever use JavaScript (and completely deprecate its usage). Evaluating inline JavaScript is terribly hackish, is not supported in all JS-environments, and makes .less files a mess of half-CSS-looking, half-JS-looking oatmeal. (See: Lesshat.) Ideally, we need Less library authors like you to work with the Less community, propose solutions, and make pull requests. That's why I've been pushing for things like plugin architecture, a proper Less.js API, auto-loading options, etc. All the things a library like Less hat might need to create clean code.

At the same time, there are some things that Lesshat may be doing wrong in its architecture approach which you may not be aware of, so some of the hoops you've had to jump through may be as a result of Lesshat's design. Often by proposing issues / solutions, other people in the community might know of a way to meet your requirements using Less in a way that's cleaner.

@matthew-dean
Copy link
Member

Now, to put this thread back on track, I notice that, in the example, the reason this is being proposed is not because the value is a string at all, such as something that will be evaluated as a multi-line CSS string, but basically an "escaped" string to pass in a set of keyframe values.

Shouldn't we instead look at how to pass in a set of declarations like that into a mixin, unescaped? Keyframes are especially hard to solve with Less, and I've never figured out a great solution. Multi-line strings still seems to be circumventing the problem.

@jonschlinkert
Copy link
Contributor

some of the hoops you've had to jump through may be as a result of Lesshat's design.

Well, yeah, my thoughts exactly. with the bottom line being that if that time had been spent contributing directly to Less.js, there wouldn't have been so many hoops to jump through with LESS HAT (e.g. LESS HAT wouldn't be such a mess of bad hacks) and everyone in the community would have benefited from the effort, not just your company.

@seven-phases-max
Copy link
Member

Shouldn't we instead look at how to pass in a set of declarations like that into a mixin, unescaped? Keyframes are especially hard to solve with Less

+1. I was thinking to at least start to do something in this direction but no results so far...
(At first we'll need @keyframes name interpolation, i.e. @keyframes @var or @keyframes @{var}. Then something like #965 (which is basically "pass in a set of declarations like that into a mixin"). Though some handy keyframe mixins would be possible with "scoped or tagged" callbacks before #965.

@jonschlinkert
Copy link
Contributor

Shouldn't we instead look at how to pass in a set of declarations like that into a mixin, unescaped?

Agreed as well. this is only nomenclature, but I think this is a better use case for the term "include" than others I've seen. I also have seen use of "raw", implying that code won't be evaluated before it's "copied in". e.g. @raw: "foo"

I'm sure there are other ways to approach this, but I agree this kind of feature would be useful. and in other use cases as well.

@matthew-dean
Copy link
Member

Hmm....

So we have this problem that's essentially: I have a set of CSS blocks that I want to put in other CSS blocks. Maybe we've been overthinking this. What about something simple like:

.keyframes(@name, @rules) {
  @-webkit-keyframes @{name} { @rules }
  @keyframes @{name}  { @rules; }
}
@block @myBlock {  // or @rules or @container, etc
    from { opacity: 1; }
    to { opacity: 1; }
}
.keyframes("foo", @myBlock);

For issue #965:

.mobile(@rules) {
  @media all and (max-device-width: 480px) {
    @rules;
  }
}
@block @rules {
   .mobile {
     property: value;
     foo: bar;
   }
}
.mobile(@rules);

Alternatively, allow mixins to be passed into mixins. (Best / most flexible solution??)

.mobile(@rules) {
  @media all and (max-device-width: 480px) {
    @rules;
  }
}
.mobile-rules() {
   .mobile {
     property: value;
     foo: bar;
   }
}
.mobile(.mobile-rules);

Like, check this shit out:

@webkit: false;

.keyframes(@name, @rules, @prefix: "") {
  @@{prefix}keyframes @{name} { @rules };
}
.frames(@prefix: "") {
    from { @{prefix}perspective: 300px; }
    to { @{prefix}perspective: 600px; }
}
.keyframes("foo", .frames("-webkit-"), "-webkit-") when @webkit;
.keyframes("foo", .frames);

Why not just allow a mixin to evaluate and pass its evaluated block into a variable, and then just reference the variable? It still looks like plain ol' regular LESS to me.

@matthew-dean
Copy link
Member

Ah, I see similar ideas have been discussed on #1640.

@matthew-dean matthew-dean mentioned this pull request Feb 1, 2014
@matthew-dean
Copy link
Member

AMENDMENT:

I realized that to be consistent with interpolation, variables used to reference blocks should probably look like:

.mobile(@rules) {
  @media all and (max-device-width: 480px) {
    @{rules};
  }
}

@seven-phases-max
Copy link
Member

@matthew-dean, for your first example I would prefer this syntax, e.g.:

.keyframes(@name, @rules) {
  @-webkit-keyframes @{name} { @rules(); }
  @keyframes @{name} { @rules(); }
}
.block() {  // it's really just an ordinary mixin
    from { opacity: 1; }
    to { opacity: 1; }
}
.keyframes("foo", .block);

This is a bit easier to implement (and provides bonus of the .block allowed to be a parametric mixin, i.e. the animation itself may be also customizible before it's assigned to @keyframes), but then it's not clear how to pass a block directly as mixin parameter. (Actually #965 looks more like two related features in one: 1. "pass/assign an expanded block" 2. "pass/assign a block (= mixin) by reference".)

@seven-phases-max
Copy link
Member

Just in case. It's usually missed that it is possible to "pass" blocks to a mixin in indirect way w/o any #965 or similar. A block can be implemented as a callback mixin with a predefined name. The only problem is that this predefined name makes things difficult when we need more then one such callback per scope, but there're a few workarounds like "tagged callbacks" (discussed here for example) or "scoped callbacks" (like I used there). In context of @keyframes, here is valid Less code examples:

1. Using "scoped callbacks":

& { .keyframes(name-1); .-() {
    from {opacity: 0;}
    to   {opacity: 1;}
}}

& { .keyframes(name-2); .-() {
    from {color: red;}
    to   {color: blue;}
}}

.keyframes(@unused-name) {
    @keyframes cant-interpolate-name-yet {.-()}
}

2. Using "tagged callbacks":

.keyframes(name-1); .-(name-1) {
    from {opacity: 0;}
    to   {opacity: 1;}
}

.keyframes(name-2); .-(name-2) {
    from {color: red;}
    to   {color: blue;}
}

.keyframes(@unused-name) {
    @keyframes cant-interpolate-name-yet {.-(@unused-name)}
}

It's just has quite confusing syntax and also is pretty verbose, so I usually reference #965 (or more specifically, "features proposed in #965": [1] and [2] in particular, not the issue itself) as a solution to similar problems.

@matthew-dean
Copy link
Member

@seven-phases-max Oh, interesting, so have the ability to have pass in a mixin reference, rather than evaluate the mixin. That works too.

@matthew-dean
Copy link
Member

You're right, your way is cleaner, and still serves the same purpose.

@matthew-dean
Copy link
Member

Oh, and since we're assigning a mixin to a variable via a mixin, we might as well allow just assigning mixins to variables that AREN'T in mixins:

@myVar: .myMixin;

@myVar();  // executes .myMixin()

Which is, of course, different from:

@myVar: ".foo";

@{myVar}();  // executes .foo();

The first being a direct mixin reference, the second interpolating a string.

@matthew-dean
Copy link
Member

Ah, and I see you proposed the same on #965. I missed that, sorry. Of anything I've seen, I think that's the most straightforward solution, and it looks like we had a similar conclusion. I'd say +1 for implementation of assigning mixins to vars, and passing mixin references to mixins as parameters.

If we can implement this, I think we can close a pile of open issues.

@dantman
Copy link

dantman commented Feb 1, 2014

@myVar: ".foo";

@{myVar}();  // executes .foo();

Something to keep in mind when fixing this is a behaviour I personally consider a bug in that this:

@myVar: ".foo";

@{myVar} {
  content: "Hello World!";
}

Actually evaluates to:

".foo" {
  content: "Hello World!";
}

Anything quoted you use in a selector currently (annoyingly) remains quoted. Which leads to fun situations like:

@unquoted: orange;
@quoted: "orange";

.color-@{unquoted},
.color-@{quoted} {
  color: orange;
}
.color-#ffa500,
.color-"orange" {
  color: orange;
}

That'll probably need fixing before that syntax could be implemented.

@seven-phases-max
Copy link
Member

you have to know to pass a mixin that will be called with certain arguments, which means you have code in 3 places that is all linked

It's just an example. The .animation mixin itself can be very smart too :) Yes, it is as complex feature as a javascript (or whatever mainstream language) callbacks feature is (actually it is simply a "generic callbacks" for Less). That may look like an overkill, especally assuming that initially Less was not supposed to be a programming language, but it became a one anyway a while ago, so... Either way my initial assumption was that @mixin-name() is much easier to implement then full-featured {} block inside a call parameters list so despite it looks like quite complex feature it has its chances to be implemented earlier :).

@matthew-dean
Copy link
Member

I think its un-needed complexity - you have to know to pass a mixin that will be called with certain arguments, which means you have code in 3 places that is all linked

Keep in mind the context. As @seven-phases-max mentioned, while that example does provide some complexity, all we're doing here is trying to pass a block by reference. And the best way we have to define blocks is via mixins. So the most common use case will be a mixin that executes with no parameters. But, sure if the developer wants to add more complexity, it adds some powerful combinations.

The compexity that they CAN create should not be confused with the complexity of the proposal, which it really is not. It's assigning a mixin to a variable, and calling that variable as a mixin, which is pretty straightforward (I'm speaking conceptually, not algorithmically).

Also, if we can do this:

@a: .a;

It seems unnecessary to do this:

.keyframes(animation-2, selector(.some-mixin));

A mixin name cannot currently conflict with any keywords, can it?

@lukeapage
Copy link
Member

Either way my initial assumption was that @mixin-name() is much easier to implement then full-featured {} block inside a call parameters list so despite it looks like quite complex feature it has its chances to be implemented earlier :).

I think the mixin bit is more complex to handle - you have to abstract out or use mixin call, you have to support calling with arguments and you have to parse a "selector"

The other part of the proposal should just involve creating a new ast node (like expression) that supports calling a new node that absorbs {} and calls rule for everything inside it. That should only be valid when assigning variables (not properties) and passing arguments. Then you need to make sure an error is caused if that is evaluated anywhere but the @call() context.

Hrmm actually they are probably equal complexity to implement! I'd still go for the blocks before the mixin call.

Keep in mind the context. As @seven-phases-max mentioned, while that example does provide some complexity, all we're doing here is trying to pass a block by reference. And the best way we have to define blocks is via mixins. So the most common use case will be a mixin that executes with no parameters. But, sure if the developer wants to add more complexity, it adds some powerful combinations.

Its the paramaters that concern me mainly in terms of adding complexity

The compexity that they CAN create should not be confused with the complexity of the proposal, which it really is not. It's assigning a mixin to a variable, and calling that variable as a mixin, which is pretty straightforward (I'm speaking conceptually, not algorithmically).

I agree its not a complex proposal, it does however make use of the language more complex by adding another way of doing things. Thats what I am talking about. And I think we shouldn't add things which are "cool" unless we have concrete use-cases for them and think people will actually use that way of doing things.

Also, if we can do this:

@a: .a;

It seems unnecessary to do this:

.keyframes(animation-2, selector(.some-mixin));

A mixin name cannot currently conflict with any keywords, can it?

so 1, as I said, the first bit only compiles because originally less tried to be clever and just ignore values it didn't understand. Thats why you can't use .a as a value everywhere, only on properties and variable assignments.

and yes a mixin name can conflict with a keyword. A mixin name can take the form .mixin or #mixin and you can also call mixins as part of simple selectors .mixin > #mixin.

edit I forgot you cannot use mixins without a . or a hash so no, currently mixins don't directly conflict with keywords. I'm still against it for the reasons below.

If we start letting selectors be used as values then we are opening ourselves up for a whole load of future issues if our mixin syntax is allowed to become more like selectors or if css values are introduced that look like selectors. Thats why I want to keep selectors and values seperate. At the moment the only way of defining a selector (unless it parses by fluke) is this

@sel: ~".selector";

we don't have to use a function called selector, I just very strongly feel we need some unque way of the parser being able to parse a selector rather than trying to work out whether it is a selector or a value. Since I think we need this anyway, I don't think we should make an exception for mixin selectors. I'm not sure if I like this but we could use a jquery like syntax

@sel: $(.selector);

which is shorter.

@SomMeri
Copy link
Member

SomMeri commented Feb 4, 2014

I like the @sel: $(.selector). There are already requests to allow any selector as mixin and this would make clear what user meant. jQuery like syntax is also great bonus - symbols are hard to search for and jQuery is popular so people will be able to guess what it means.

@matthew-dean
Copy link
Member

On the syntax front, remember that in Less, we traditionally look for something that either parallels a CSS syntax or is CSS-like. CSS normally leans towards keywords. A $() syntax is more JavaScript.

@lukeapage You know more of the parser side, so if it's more complicated in the mixin call to do direct assignment, no problem.

So, if we need to wrap it, "mixin" feels more intuitive to me than "selector" and a keyword is Less/CSS-like to me:

@mixVar: mixin(.block);

// or
.keyframes(animation-2, mixin(.some-mixin));

//or
.keyframes(animation-2, mixin({ property: value; }));

This implies that you can only "execute" the variable with (); whereas "selector" implies anything.

....Unless your suggestion is that someone would be able to pass in any matching selector, and you're defining a mixin as a selector? So, it would somewhat borrow the :extend algorithm? I think I see where your brain is going with this, especially since Less somewhat handles the difference between mixins and selectors transparently.

Huh. I never thought about being able to pass in and output the content of any matching selector, along with executing a mixin. That's kind of even cooler (if I'm following you correctly). But I wonder if "selector" is intuitive to refer to mixins for the layperson? Maybe supporting selector() and mixin()? Just spitballing.

@lukeapage
Copy link
Member

On the syntax front, remember that in Less, we traditionally look for something that either parallels a CSS syntax or is CSS-like. CSS normally leans towards keywords. A $() syntax is more JavaScript.

thats the reason I said I'm not sure if I like this. But I do very much like the short syntax.

So, if we need to wrap it, "mixin" feels more intuitive to me than "selector" and a keyword is Less/CSS-like to me:

there is a generic need to be able to describer a selector. since it would be a special "magic" function that made the parser act differently (like url) I would rather keep it to 1 for selector, not one for selector and 1 for mixin.

.keyframes(animation-2, mixin({ property: value; }));

we do not need to wrap rule blocks, that does not have the same problems

Huh. I never thought about being able to pass in and output the content of any matching selector, along with executing a mixin

No, I never meant that, I meant that the mechanism for describing a mixin should be the same as decribing a selector, I wouldn't want you to be able to mixin call any selector (though there is a seperate issue devoted to someone asking for that)

@matthew-dean
Copy link
Member

Okay, so if we aren't mixin calling any selector, then we're just talking about referencing mixins, correct? So selector() would not seem to be accurate? If it is, can you explain further?

@lukeapage
Copy link
Member

@matthew-dean a mixin call is a subset of a selector and how much of a subset it is could change in the future.

See

#1859

I implemented this feature - or at least phase 1 - @seven-phases-max I think this is simpler than the second case..

My main concern is evident from the tests.. its difficult to see whats a mixin call and whats a mixin definition. I wonder if there is something in the syntax that can be done to improve that ala ES6 inline function calls () => {}. Anyway, open to suggestions and I think we should move any conversation over phase 1 to that pull request and open another issue for passing mixins and then after that passing arguments (although I vote to wait and see what people do with the first syntax first).

@lukeapage
Copy link
Member

And now for 1.7 we have everything needed.. this can be closed?

@matthew-dean
Copy link
Member

You said you only implemented phase 1? Which part was phase 1? And if so, should we leave open if there are other phases to implement?

@seven-phases-max
Copy link
Member

I guess this can be closed (#1859 entirely covers the subject use-case, and other yet more advanced cases/features we discussed above are probably better to have their dedicated tickets anyway. Later it will be not so easy to find anything important here hidden under the "Multiline Strings" title).

@lukeapage
Copy link
Member

Yes see my comments above for links to pull. This bug is about multiline
strings that's why I want to close.

@matthew-dean
Copy link
Member

Right ok.

@lukeapage lukeapage closed this Feb 13, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet