How to create a wrapper function in stylus? - stylus

I want to create a function that wraps another built-in function in stylus. Something like:
myFunction(color, amount)
darken(color, amount)
I want to create multiple themes for a project, and in that some themes are dark and some are light, so for hover I want to lighen() the background-color and for the others darken(), and use myFunction() in a file that is common among all the themes, only changes the function definition in each theme.
What I want to know: Is it possible at all? Or if there is any other mechanism for function polymorphism in stylus, any method to be able to change the definition of function dynamically.
What I have tried:
First I tried to wrap simply like:
inHover (color, amount)
darken(color, amount)
But I got:
cmd.exe /D /C E:/node/nodist/bin/stylus.cmd definitions.styl
E:\node\nodist\bin\node_modules\stylus\bin\stylus:662
throw err;
^
RangeError: definitions.styl:20:10
16|
17| /* Functions */
18|
19| inHover (color, amount)
20| darken(color, amount)
----------------^
21|
Maximum call stack size exceeded
at darken() (E:/node/nodist/bin/node_modules/stylus/lib/functions/index.styl:128:21)
at "inHover (color" (definitions.styl:18:16)
at Evaluator.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:162:34)
at Evaluator.visitIdent (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:533:23)
at Evaluator.Visitor.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\index.js:28:40)
at Evaluator.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:156:18)
at Evaluator.visitExpression (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:630:26)
at Evaluator.Visitor.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\index.js:28:40)
at Evaluator.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:156:18)
at Evaluator.visitIdent (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:533:23)
at Evaluator.Visitor.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\index.js:28:40)
at Evaluator.visit (E:\node\nodist\bin\node_modules\stylus\lib\visitor\evaluator.js:156:18)
I cannot use blocks, since they do not accept arguments.
My code:
HTML code:
<html>
<head>
<link href='/css/themes/my_theme/index.css' rel='styleSheet'/>
<body ng-app='app'>
<!-- Body defination -->
</body>
</html>
/css/themes/my_theme/index.styl file:
#import 'definitions.styl'
#import '../../site.styl' /* All the common css styles*/
myFunction(color, amount)
darken(color, amount)
/css/themes/my_theme/definitions.styl file:
/* Color definitions */
colorPrimary = red
colorBackground = green
/* Functions */
inHover (color, amount)
darken(color, amount)
What I use:
stylus 0.52.4
Node 4.1.1
express 4.13.3

Well, this code works for me (try to remove the space before ( in the function definition):
inHover(color, amount)
darken(color, amount)
body
color: inHover(#c00, 10)
Compiles with Stylus 0.52.4 to:
body {
color: #900;
}

Related

Array of one element in Stylus

When I define new component, I need to specify how much this component must retire from other components (by other words, define margin-top; mixin WhenItJustAfter do it), and how much other components must retire from new component (mixin RulesForTargetThatGoingJustAfterIt do it):
WhenItJustAfter(targetElementSelector)
/{targetElementSelector} + {selector()}
{block}
RulesForTargetThatGoingJustAfterIt(targetElementSelector)
/{selector()} + {targetElementSelector}
{block}
provideBlockquoteComponent(
CSS_Namespace = "Blockquote",
positionalRelationshipWithOtherComponents = null
)
.Blockquote
// ...
if positionalRelationshipWithOtherComponents
for component in positionalRelationshipWithOtherComponents
+WhenItJustAfter("." + component.CSS_Class)
margin-top: component.whenJustBeforeIt
+RulesForTargetThatGoingJustAfterIt("." + component.CSS_Class)
margin-top: component.whenItJustAfter
Now we can define positional relationship between components as (sorry for long line, I did not explore yet how elegantly to break it in Stylus):
provideBlockquoteComponent(
positionalRelationshipWithOtherComponents: ({ CSS_Class: "AlertBox", whenJustBeforeIt: 6px, whenItJustAfter: 12px } { CSS_Class: "Image", whenJustBeforeIt: 12px, whenItJustAfter: 22px })
)
It will work for arrays of two and more elements; debug output will be:
inspect: {"CSS_Class":"(\"AlertBox\")","whenJustBeforeIt":"(12px)","whenItJustAfter":"(22px)"}
inspect: {"CSS_Class":"(\"Image\")","whenJustBeforeIt":"(12px)","whenItJustAfter":"(22px)"}
But what if positionalRelationshipWithOtherComponents will contain just one element?
provideBlockquoteComponent(
positionalRelationshipWithOtherComponents: ({ CSS_Class: "AlertBox", whenJustBeforeIt: 6px, whenItJustAfter: 12px })
)
We get:
inspect: 'CSS_Class'
inspect: 'whenJustBeforeIt'
inspect: 'whenItJustAfter'
Thereby positionalRelationshipWithOtherComponents is not array for Stylus anymore; Stylus iterated the properties keys instead of array elements.
I did not found the array literal for Stylus. If it exists, please teach me this literal, otherwise please suggest the workaround.

ReasonML binding function with config having fixed string values

Lets say, that I have this function in Javascript which can generate string based on proper configuration:
function func(config) {
// ...
}
also, let's assume, that the config variable has structure as below (all of these can be not given to function call):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
How to create proper binding for this? I'm stuck with:
[#bs.deriving abstract]
type options = {
[#bs.optional]
color: [#bs.string] [ | `blue | `red | `green ]
[#bs.optional]
number: int,
[#bs.optional]
other: [#bs.string] [ | `x | `y ]
}
[#bs.module]
external func: options => string = "func";
But it does not work when trying to use like this:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
The color and other values are integers, not strings.
This is a case of a JavaScript idiom for named parameters (objects with optional fields), needing to be adapted to the OCaml/ReasonML idiom (functions with actual labelled parameters). You would do this in three steps. Step 1, as Glenn showed, define an external for the config:
type config;
[#bs.obj] external config: (
~color:[#bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[#bs.string] [`x | `y]=?,
unit,
) => config = "";
Step 2, bind to the JavaScript function using the JavaScript style of the config object:
[#bs.val] external func: config => string = "";
Step 3, wrap the JavaScript function binding in an OCaml-idiomatic function with labelled parameters:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
You can use it like this:
let result = func(~color=`blue, ());
The #bs attributes are often poorly thought out hacks that you shouldn't expect to work well with other attributes, or really with anything other than exactly what the documentation explains or shows examples of. However, if an attribute is used where it is not intended you'll usually at least get a warning about the attribute being unused, which your code does.
#bs.string in particular only works on types at the outermost level of externals, i.e. on types whose values will be passed directly to the external function. There is also a way to create JavaScript objects using external functions which also happens to use less magic and give you much more control over the API. As far as I'm aware, the only downside compared to #bs.deriving is that you can't override field names using something like #bs.as. They have to be valid OCaml identifiers.
Here's your example implemented using an external function annotated with #bs.obj:
type options;
[#bs.obj] external options : (
~color:[#bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[#bs.string] [`x | `y]=?,
unit
) => options = "";
To use it you call it exactly as with #bs.deriving:
let config = options(~color=`blue,~number=123, ~other=`x, ());
But even with this I've encountered edge cases where integer values are passed in instead of strings. For this reason I tend to avoid the polymorphic variant attributes altogether and instead use ordinary variants along with conversion functions. This has the added benefit of being more idiomatic, blending in better and being more interoperable with non-BuckleScript code.
Here's what your example might look like using this approach:
type color = Blue | Red | Green;
let colorToString = fun
| Blue => "blue"
| Red => "red"
| Green => "green";
type other = X | Y;
let otherToString = fun
| X => "x"
| Y => "y";
[#bs.obj] external options : (
~color:string=?,
~number:int=?,
~other:string=?,
unit
) => options = "";
[#bs.module] external func: options => string = "func";
let func = (~color=?, ~number=?, ~other=?, ()) =>
func(options(
~color = ?Belt.Option.map(color, colorToString),
~number?,
~other = ?Belt.Option.map(other, otherToString),
()));
let config = func(~color=Blue,~number=123, ~other=X, ());
This is because in reality, those values are variants, instead of trying to make it exactly like JavaScript, I would rather try something more idiomatic to Reason:
type color = Blue | Green | Red;
type coords = X | Y;
type config = {
color,
coords,
number: int
};
let func = (config: config) => "something"
And then inside your function actually return strings (if that is what you really need) by pattern matching on the correct values provided to config.
See the working code here.
Hope it helps!

How to display text on GTK label using two different fonts?

I have a GTK label and I am displaying text on it in Arial Rounded Mt Bold by using following code:
PangoFontDescription *df;
df = pango_font_description_new ();
pango_font_description_set_family(df,"Arial Rounded Mt Bold");
pango_font_description_set_size(df,fontsize*PANGO_SCALE);
gtk_widget_modify_font(Message_Label, df);
gtk_label_set_text(GTK_LABEL(Label), "Hello World");
pango_font_description_free (df);
Now this Hello World is displayed in Arial Rounded Mt Bold. But what if I want to display Hello in Arial Rounded Mt Bold and World in some other font for example Arial. Is this possible in GTK label. I am doing it in C. Any advice or any useful links. Thanks.
gtk_widget_modify_font() is deprecated and won't let you do what you want.
You can use a PangoAttrList, which combines attributes (including the individual components of a PangoFontDescriptor) over ranges of text. For instance:
PangoAttrList *attrlist;
PangoAttribute *attr;
PangoFontDescription *df;
attrlist = pango_attr_list_new();
// First, let's set up the base attributes.
// This part is copied from your code (and slightly bugfixed and reformatted):
df = pango_font_description_new();
pango_font_description_set_family(df, "Arial Rounded MT");
pango_font_description_set_size(df, fontsize * PANGO_SCALE);
pango_font_description_set_weight(df, PANGO_WEIGHT_BOLD);
// You can also use pango_font_description_new_from_string() and pass in a string like "Arial Rounded MT Bold (whatever fontsize is)".
// But here's where things change:
attr = pango_attr_font_desc_new(df);
// This is not documented, but pango_attr_font_desc_new() makes a copy of df, so let's release ours:
pango_font_description_free(df);
// Pango and GTK+ use UTF-8, so our string is indexed between 0 and 11.
// Note that the end_index is exclusive!
attr->start_index = 0;
attr->end_index = 11;
pango_attr_list_insert(attrlist, attr);
// And pango_attr_list_insert() takes ownership of attr, so we don't free it ourselves.
// As an alternative to all that, you can have each component of the PangoFontDescriptor be its own attribute; see the PangoAttribute documentation page.
// And now the attribute for the word "World".
attr = pango_attr_family_new("Arial");
// "World" starts at 6 and ends at 11.
attr->start_index = 6;
attr->end_index = 11;
pango_attr_list_insert(attrlist, attr);
// And finally, give the GtkLabel our attribute list.
gtk_label_set_attributes(GTK_LABEL(Label), attrlist);
// And (IIRC this is not documented either) gtk_label_set_attributes() takes a reference on the attribute list, so we can remove ours.
pango_attr_list_unref(attrlist);
You can also use gtk_label_set_markup() to use an HTML-like markup language to set both text and styles in one go:
gtk_label_set_markup(GTK_LABEL(Label),
"<span face=\"Arial Rounded MT\" size=\"(whatever fontsize * PANGO_SCALE is)\" weight=\"bold\">Hello <span face=\"Arial\">World</span></span>");
// Or even...
gtk_label_set_markup(GTK_LABEL(Label),
"<span font=\"Arial Rounded MT Bold (whatever fontsize is)\">Hello <span face=\"Arial\">World</span></span>");

stylus mixin with &:nth-of-type

I would like something like this
number(x)
&:nth-of-type(x)
Mostly just for readability - and for a basic example of when I might need to use the & in a mixin...
li //
number(1)
color: red
number(2)
color: blue
To yield...
li //
&:nth-of-type(1)
color: red
&:nth-of-type(2)
color: blue
Is this possible? Escaping ... ? ? ?
for my break-points... i use a variable --- but can't here
#media break-point-1 etc...
I'm afraid you can create shortcut like that
But you can use this mixin
setColors(colorList)
for col, index in colorList
&:nth-child({index})
color: col;
setColors(red blue);
This is a very old question and I am sure you found a solution a long time ago but there isnĀ“t an accepted answer and maybe is useful for other users.
To use variables in selectors, they must be enclosed in braces (interpolation). To get the content in the mixin, use the block mixin feature:
Stylus
number(x)
&:nth-of-type({x})
{block}
li
+number(1)
color red
+number(2)
color blue
CSS:
li:nth-of-type(1) {
color: #f00;
}
li:nth-of-type(2) {
color: #00f;
}

Why does my PowerShell script prompt for permission to add items to arrays?

I have a PowerShell script with the following excerpt:
foreach ($pc in $ComputerName) {
$appnames = $appnames | Sort-Object
Write-Debug "Number of entries in `$appnames = $($appnames.count)"
if ($AsHTML) {#Switch Parameter
Write-Verbose "Generating HTML Report..."
$th = "<TR><TH>Application Name</TH>" #Create Top header
foreach ($pc in $ComputerName) {
$th += "<TH>$pc</TH>" #Another header for each pc
}
$th += "</TR>" #Header finished
$rows = ""
foreach ($app in $appnames) {
$rows += "<TR><TH>$app</TH>"
foreach ($pc in $ComputerName) {
Write-Debug $RegistryEntries[$pc].Value[$app]
$currentApp = $RegistryEntries[$pc].Value[$app]
if ($currentApp) {
if ($currentApp.DisplayVersion) {
$status = $currentApp.DisplayVersion
} else {
$status = "Version-nr. N/A"
}
} else {
$status = "Application N/A"
}
$rows += "<TD>$status</TD>" #Intersection cell for each pc
}
$rows += "</TR>"
}
Write-Verbose "Finishing html report..."
$html = "
<html>
<head>
<style>
body { background-color:#FFFFCC;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid #000033;
border-collapse:collapse; }
th { color:white;
background-color:#000033; }
table, tr, td, th { padding: 0px; margin: 0px }
table { margin-left:10px; }
</style>
<Title>Application versions Report</Title>
</head>
<body>
<table>
$th
$rows
</table>
</body>
</html>"
}
}
So, to explain the wall of text above a bit;
$RegistryEntries is a Hashtable of Hashtables, with the top-level keys being computer names, and the low-level hashtable keys being application names found in the Uninstall part of the registry. The corresponding values to the Application-name-keys are custom PSObjects with three general properties: .Displayname, .DisplayVersion, and .UninstallString. (Not all objects have all of the three properties, but each object has at least one).
What I hope to achieve with this HTML-table is to get some kind of "pivot-table" (ref. Wikipedia entry for Pivot Tables, but not quite), where I can get Application Names on the Y-axis, and computer names on the X-axis, and the Version number of said application on said computer where they intersect.
So again, with that in mind, could someone help me understand why my script when run prompts me in the shell for permission to add application names to the array $appnames (elsewhere in the script), as well as doing the same with the HTML input that is being put into $rows?
Another thing which is a bit on the side (maybe even off-topic), my $RegistryEntries object, the hashtable of hashtables, is for some reason not possible to access in the way I do it on the two following lines:
Write-Debug $RegistryEntries[$pc].Value[$app]
$currentApp = $RegistryEntries[$pc].Value[$app]
Would anyone be able to tell me why?
To sum up/TL;DR:
Why does my function when trying to add items to an array created inside the script prompt me for permission to do just this in the shell?
With the custom object I've described above holding the data I want to display in my HTML table, what am I doing wrong in trying to access it in the above code excerpt?
PS: The script works in the sense that if I sit throughout all the prompts I get in the shell, hitting A + Return all the time, I will get a HTML table of the kind that I want, but all the cells where an application name interstices a computername will say "Application N/A".
I guess you have your $DebugPreference and/or VerbosePreference set to Inquire which will prompt every time Write-Debug or Write-Verbose are called, respectively:
Confirm
Continue with this operation?
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help (default is "Y"):
You probably want to set them to Continue instead. Another source might be the -Debug switch.
Regarding your second question, it's a little long to explain, but for arguments to commands you have to put such expressions in parentheses:
Write-Debug ($RegistryEntries[$pc].Value[$app])
$currentApp = $RegistryEntries[$pc].Value[$app]

Resources