ReSharper 8 - Live Template Macros - HotspotItems - macros

I am currently using ReSharper V8.1. I've only recently began using ReSharper and have found some interest in their LiveTemplate Macros. I've conjured up a solution to return a list of HotspotItems from a constant, similar to ReSharper's predefined macro "Comma-delimited list of values". In the method I take the constant variable of the template parameter and do a split string on them to provide a collection of HotSpotItems. Unfortunately it doesn't work if I use the macro more than one time within a template. Below is an extreme hack job showing my implementation of the method HotspotItems of IMacroImplementation.
I am hoping that someone out there may have done some work in this area and could possibly provide an example of how they've implemented IMacroImplementation which provides a list of items from a constant and also allows for multiple uses within a single template.
Thank you.
public override HotspotItems GetLookupItems(IHotspotContext context)
{
HotspotItems hotSpotItems = null;
foreach (var hotspot in context.HotspotSession.Hotspots)
{
if (hotspot.Expression != null && ((MacroCallExpressionNew)hotspot.Expression).Definition is Macros.DisplayMultipleItems)
{
//hotspot.CurrentValue
var multiItems = ((MacroCallExpressionNew) hotspot.Expression).Definition as DisplayMultipleItems;
if (!multiItems.ItemSet)
{
var expression = hotspot.Expression as MacroCallExpressionNew;
IMacroParameterValueNew baseValue = expression.Parameters[0].GetValue(context.SessionContext.Solution.GetLifetime(), context.HotspotSession);
string templateValue = baseValue.GetValue();
multiItems.ItemSet = true;
if (!string.IsNullOrEmpty(templateValue) && templateValue.Split(',').Any())
{
var lookupItems = templateValue.Split(',').Select(param => new TextLookupItem(param)).Cast<ILookupItem>().ToList();
if (hotSpotItems == null)
hotSpotItems = new HotspotItems(lookupItems);
else
{
foreach (var item in lookupItems)
{
hotSpotItems.Items.Add(item);
}
}
}
}
}
}
return hotSpotItems;
}

You should fire up dotPeek and point it to the ReSharper bin directory and take a look at ListMacroDef and ListMacroImpl, which is the implementation for the comma-delimited list macro.
The definition derives from SimpleMacroDefinition. It gets given the parameters in the call to GetPlaceholder, looks at the first and splits it by comma, returning the first item as the placeholder.
ListMacroImpl is just as simple. Its constructor has an [Optional] parameter of type MacroParameterValueCollection. This is the list of parameter values specified in the hotspot editor. You'll want to check for null and take the first parameter, which will be your delimited list. It then overrides GetLookupItems and returns HotspotItems.Empty if the parameter value is null, or parses the value and returns a list of TextLookupItem.
You don't need to look at the session and list of hotspots - that will get you all hotspots in the session, when you're only interested in the current hotspot, and ReSharper will create a new IMacroImplementation for each hotspot and give you those values in your constructor.

Related

How to use if else in ARM template azure

I have created sample function here in c# which set the location value based on the parameter. I want to write below expression by using arm template style format.
public static Main(string name)
{
string location = string.Empty;
if(name == "uksouth")
{
location = "UKS";
}else if(name == "ukwest")
{
location = "UKE";
}else if(name == "IndiaWest")
{
location = "INDW";
}
else {
location = "INDS";
}
}
I have written this for one match condition, but i want to return value based on the user resource group.
"value": "[if(equals(resourceGroup().location,'uksouth'), 'UKS', 'EUS')]"
Unfortunately, ARM templates don't provide the equivalent of a "switch" mechanism, which is what might make this easier. However, you can nest multiple if statements. The syntax is a bit clunky, but this should be the equivalent of the code you've written:
"value": "[if(equals(resourceGroup().location,'uksouth'), 'UKS', [if(equals(resourceGroup().location,'ukwest'), 'UKE', [if(equals(resourceGroup().location,'IndiaWest'), 'INDW', 'INDS')])])]"
Here's the same code with a little formatting applied to make it more obvious what's happening here:
"value": "
[if(equals(resourceGroup().location,'uksouth'),
'UKS',
[if(equals(resourceGroup().location,'ukwest'),
'UKE',
[if(equals(resourceGroup().location,'IndiaWest'),
'INDW',
'INDS')])])]
"
You might also consider the approach described in this answer for a bit of a cleaner solution.
Try defining a variable that is an object used like a hashtable. Retrieve different properties from the object by key-name, accessing the properties as key-value pairs. I use something very similar to lookup values inside my ARM templates.
"variables" {
"locationShorten": {
"uksouth": "UKS",
"ukwest": "UKE",
"IndiaWest": "INDW",
"IndiaSouth": "INDS"
},
"locationShort": "[variables('locationShorten')[resourceGroup().location]]"}
Microsoft defines an object's properties as key-value pairs. "Each property in an object consists of key and value. The key and value are enclosed in double quotes and separated by a colon (:)."
Source: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/data-types#objects
As for the documentation on using [] to access object properties, I can no longer find it for JSON but it is there for BICEP. "You can also use the [] syntax to access a property."
Source: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/data-types#objects

Is there a dart function annotation that makes the type checker do type narrowing or condition assertions

Is there a construct that communicates to the type checker a function's post-condition?
For example, in typescript it is possible to say
function assertIsNumber(value: any): asserts value is number {
if (typeof value !== 'number') {
throw new TypeError();
}
}
I would like to be able to do something like the following in dart:
class SomeClass {
int? value;
_checkPreconditions() {
if(value == null) {
throw MyPreconditionError()
}
// ...
}
somefunc() {
_checkPreconditions();
// here we know `value` is a non-null int.
final sum = value + 5;
}
}
I understand I could coerce the value to non-null sum = value! + 5, but I would prefer to allow the function to inform the type checker if possible.
It looks like the type system of Dart is not so powerful. The only thing that looks (from first glance) possible is to create a custom code analyzer package (or search for one that already exists).
Dart annotations don't actually do anything. They provide hints to tools such as the Dart analyzer (usually so that it can generate additional warnings), but they cannot change program behavior. Even if you could convince the analyzer to treat some variables as different types, you still wouldn't be able to compile and run your code.
Annotations can be used by code generation tools, so one possibility might be to generate a statement such as final value = this.value!; automatically. However, that would be a lot of trouble to go through (and would mean that code then would need to use this.value = 42; for assignments and would prevent your code from being analyzed directly).

Convert list of strings to an enum list (One,Two,etc)

I've searched a lot but can't find a clear answer anywhere for string list -> enum.
I've got a list of strings that I want to turn into an enum that I can select from in Unity inspector.
Specifically, I'm trying to make an enum list of all the currently set-up Input buttons from project settings. I've got all the names, just don't know how to make it an enum or similar. Ideally showing up like a KeyCode variable in inspector.
Currently trying (and failing) with:
foreach (string s in names)
{
if (Enum.TryParse(s, true, out list))
Debug.Log(list);
else Debug.Log("FAILED");
}
"names" = static List<string> names;
"list" = static MyList list;
"MyList" = enum MyList { Null }
Returns "FAILED" 58 times for only 29 Input axis.
I want a simple solution, so if its not possible or relatively simple, I'll work out something else.
Code for getting the "names" list of strings (Works correctly):
var inputManager = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset")[0];
SerializedObject obj = new SerializedObject(inputManager);
SerializedProperty axisArray = obj.FindProperty("m_Axes");
if (axisArray.arraySize == 0)
Debug.Log("No Axes");
for (int i = 0; i < axisArray.arraySize; ++i)
{
var axis = axisArray.GetArrayElementAtIndex(i);
var name = axis.FindPropertyRelative("m_Name").stringValue;
names.Add(name);
}
Normally you can do
foreach (string colorName in Enum.GetNames(typeof(Colors))) which will iterate the names of the enums.
In your code above you havent shown what list is, nor where names has come from. However.
enum Things
{
Item1 = 0,
Item2 = 1
}
You can get the name from string name = Enum.GetName(typeof(Things), (int)Things.Item2) and you can get values from names with int value = (int)Enum.Parse(typeof(Things), nameOfThing)
So depending on what you actually want in a list and what you start with, iterate through and pick the relevant one
I ended up making my own solution, since (and please correct me if I'm wrong) the TryParse() and Parse() methods appear to need the enum to already contain entries with the same name (or index int) as the string to parse. This defeats the purpose for me, since I am doing this because I don't have the names in there already.
My solution ended up being to switch to having a single string input variable instead of an enum, then use Odin Inspector's ValidateInput attribute to check (for spelling errors, and) if the input variable matches any of the string entries in my dynamic list of InputManager input names (which I update manually using Odin Inspector's Button attribute and the code in the original post).
It's slightly less clean than I wanted, but does the job, so I'm satisfied.

TextCellEditor with autocomplete in Eclipse SWT/JFace?

I'd like a TextCellEditor with the standard auto-complete behaviour, that that any user nowadays expects when typing inside an input cell with a list of suggested strings. For a good working example of what I'm after, in Javascript, see this jQuery autocomplete widget.
I couldn't find a good example.
I only found (aside from some tiny variations) this TextCellEditorWithContentProposal snippet. But that leaves a lot to be desired:
It lists all the words, irrespective of the "partial word" typed in the cell (no partial matching)
When the desired word is selected, it is appended to the partial word, instead of replacing it
The interaction is ugly and non-intuitive. For example, one would expect the
Escape key to tear off the list of suggestions; again, see the Javascript example; here, it also removes the typed letters.
It looks strange to me that such an standard and useful component is not available. Or perhaps it is available? Can someone point to me to a more apt snippet or example?
The example you are linking to is a code snippet intended to showcase the API and guide you toward customizing the control to your preference.
Some of your complaints are either invalid or can easily be fixed using public API.
Let's go through them in detail.
All proposals are listed, irrespective of typed text
Note that in the snippet an org.eclipse.jface.fieldassist.SimpleContentProposalProvider is used:
IContentProposalProvider contentProposalProvider = new SimpleContentProposalProvider(new String[] { "red",
"green", "blue" });
cellEditor = new TextCellEditorWithContentProposal(viewer.getTable(), contentProposalProvider, null, null);
As suggested in its javadoc it is:
designed to map a static list of Strings to content proposals
To enable a simple filtering of the contents for the snippet, you could call: contentProposalProvider.setFiltering(true);
For anything more complex you will have to replace this with your own implementation of org.eclipse.jface.fieldassist.IContentProposalProvider.
Selection is appended to cell contents, instead of replacing it
The content proposal behavior is defined in the org.eclipse.jface.fieldassist.ContentProposalAdapter. Again a simple method call to org.eclipse.jface.fieldassist.ContentProposalAdapter.setProposalAcceptanceStyle(int) will achieve your target behavior:
contentProposalAdapter = new ContentProposalAdapter(text, new TextContentAdapter(), contentProposalProvider, keyStroke, autoActivationCharacters);
contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
Cancelling the proposal should not remove typed content
This is hard to do using just the API, since the ContentProposalAdapter does only propagate the key strokes to the opened ContentProposalPopup without storing them.
You would have to subclass ContentProposalAdapter, in order to have access to ContentProposalAdapter.ContentProposalPopup.filterText.
Most of the functionality in this snippet with sensible defaults can also be obtained in a more simple way by using an org.eclipse.jface.fieldassist.AutoCompleteField.
Here is a snippet showing you a simple implementation. You have to customize it but it give you the way.
Note, this is not a generic copy/paste of the documentation or an explanation about the doc.
String[] contentProposals = {"text", "test", "generated"};
// simple content provider based on string array
SimpleContentProposalProvider provider = new SimpleContentProposalProvider(contentProposals);
// enable filtering or disabled it if you are using your own implementation
provider.setFiltering(false);
// content adapter with no keywords and caracters filtering
ContentProposalAdapter adapter = new ContentProposalAdapter(yourcontrolswt, new TextContentAdapter(), provider, null, null);
// you should not replace text content, you will to it bellow
adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_IGNORE);
// now just put your implementation
adapter.addContentProposalListener(new IContentProposalListener() {
#Override
public void proposalAccepted(IContentProposal proposal) {
if(proposal != null && StringUtils.isNotBlank(proposal.getContent())){
// you need filter with blank spaces
String contentTextField = getFilterControl().getText();
String[] currentWords = getFilterControl().getText().split(" ");
StringBuilder textToDisplay = new StringBuilder();
if(currentWords.length > 1) {
// delete and replace last word
String lastWord = currentWords[currentWords.length-1];
textToDisplay.append(contentTextField.substring(0, contentTextField.length()-1-lastWord.length()));
textToDisplay.append(" ");
}
// add current proposal to control text content
textToDisplay.append(proposal.getContent());
yourcontrolswt.setText(textToDisplay.toString());
}
}
});
If you want more you can also have your own content proposal provider If you need a particular object instead of string or something like.
public class SubstringMatchContentProposalProvider implements IContentProposalProvider {
private List<String> proposals = Collections.emptyList();
#Override
public IContentProposal[] getProposals(String contents, int position) {
if (position == 0) {
return null;
}
String[] allWords = contents.split(" ");
// no words available
if(allWords.length == 0 || StringUtils.isBlank(allWords[allWords.length-1]))
return null;
// auto completion on last word found
String lastWordFound = allWords[allWords.length-1];
Pattern pattern = Pattern.compile(lastWordFound,
Pattern.LITERAL | Pattern.CASE_INSENSITIVE /*| Pattern.UNICODE_CASE*/); // this should be not used for better performances
IContentProposal[] filteredProposals = proposals.stream()
.filter(proposal -> proposal.length() >= lastWordFound.length() && pattern.matcher(proposal).find())
.map(ContentProposal::new).toArray(IContentProposal[]::new);
// no result
return filteredProposals.length == 0 ? null : filteredProposals;
}
public void setProposals(List<String> proposals) {
this.proposals = proposals;
}
}

Zend Framework: is there a way to access the element name from within a custom validator?

I'm writing a custom validator that will validate against multiple other form element values. In my form, I call my custom validator like this:
$textFieldOne = new Zend_Form_Element_Text('textFieldOne');
$textFieldOne->setAllowEmpty(false)
->addValidator('OnlyOneHasValue', false, array(array('textFieldTwo', 'textFieldThree')));
My validator will check that only one of those three fields (textFieldOne, textFieldTwo, textFieldThree) has a value. I want to prevent a future developer from accidentally passing the same field twice.
$textFieldOne->addValidator('OnlyOneHasValue', false, array(array('textFieldOne', 'textFieldTwo', 'textFieldThree')));
So far, my validator works perfectly, except when I pass the same field name as the field that has the valiator set on it.
In my validator, you can see that I am checking that the value (of the element with the validator set on it). I'm also checking the values of the other fields that were passed to the validator.
public function isValid($value, $context = null) {
$this->_setValue($value);
$this->_context = $context;
if ($this->valueIsNotEmpty()) {
if ($this->numberOfFieldsWithAValue() == 0) {
return true;
}
$this->_error(self::MULTIPLE_VALUES);
return false;
}
if ($this->numberOfFieldsWithAValue() == 0) {
$this->_error(self::ALL_EMPTY);
return false;
}
if ($this->numberOfFieldsWithAValue() == 1) {
return true;
}
if ($this->numberOfFieldsWithAValue() > 1) {
$this->_error(self::MULTIPLE_VALUES);
return false;
}
}
private function valueIsNotEmpty() {
return Zend_Validate::is($this->_value, 'NotEmpty');
}
private function numberOfFieldsWithAValue() {
$fieldsWithValue = 0;
foreach ($this->_fieldsToMatch as $fieldName) {
if (isset($this->_context[$fieldName]) && Zend_Validate::is($this->_context[$fieldName], 'NotEmpty')) {
$fieldsWithValue++;
}
}
return $fieldsWithValue;
}
My solution is to either...
A. Let the developer figure out there is a certain way to do it.
B. Ignore $value, forcing you to pass all the elements (which isn't much different than the first option).
or C. (if possible) Find the name of the element that called my validator in the first place and ignore it from the list of $fieldsWithValue.
I don't think there is a way to apply a validator on a form without attaching it to an element, but that would be even better, if it were an option.
How can I solve this problem?
Normaly i'd advise against such things, but, in this case I believe a static member in your class would actually provide a good solution to this problem.
With a static member, you can set it to the value in the first time the isValid is called, and check against it in subsequent calls, thus giving you a mechanism for this.
You may want to set this up to use some array in the configuration options, so that you can namespace and allow multiple instances of the validator to exist happily alongside each other for different sets.
The only problem that you really have to decide how to overcome, is where you wish to display the error, as yes the form itself does not take validators. if you want all the duplicates after the first to display an error, it is not so much of a problem.