wxStyledTextCtrl Code Completion - wxwidgets

I am designing a simple editor for Lua to use in my software written in C++ using wxWidgets. I have been searching around to find a simple example on implementing code completion using wxStyledTextCtrl in C++.
I have checked the websites of both Scintilla and wxWidgets but could not find any. I wonder if someone could help with a code snippet.

Unfortunately, I've found that the original Scintilla documentation leaves a lot to be desired, and the wxStyledTextCtrl documentation is an almost-verbatim copy of the Scintilla docs.
I recently discovered this wiki article from the ScintillaNET project and it has been quite helpful in getting started with autocompletion. The process is the same for any Scintilla implementation. I actually used it with IupScintilla.
https://github.com/jacobslusser/ScintillaNET/wiki/Basic-Autocompletion
private void scintilla_CharAdded(object sender, CharAddedEventArgs e)
{
// Find the word start
var currentPos = scintilla.CurrentPosition;
var wordStartPos = scintilla.WordStartPosition(currentPos, true);
// Display the autocompletion list
var lenEntered = currentPos - wordStartPos;
if (lenEntered > 0)
{
scintilla.AutoCShow(lenEntered, "abstract as base break case catch checked continue default delegate do else event explicit extern false finally fixed for foreach goto if implicit in interface internal is lock namespace new null object operator out override params private protected public readonly ref return sealed sizeof stackalloc switch this throw true try typeof unchecked unsafe using virtual while");
}
}
Here is a simple wxWidgets app that does the same thing:
#include <wx/wx.h>
#include <wx/stc/stc.h>
class wxTestProject : public wxApp
{
public:
bool OnInit();
void OnChange( wxStyledTextEvent& event );
};
wxIMPLEMENT_APP(wxTestProject);
bool wxTestProject::OnInit()
{
wxFrame* frame = new wxFrame( NULL, wxID_ANY, "wxTestProject",
wxDefaultPosition, wxSize(640,480) );
wxStyledTextCtrl* stc = new wxStyledTextCtrl( frame, wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxBORDER_NONE );
stc->SetLexerLanguage( "lua" );
stc->Bind( wxEVT_STC_CHANGE, &wxTestProject::OnChange, this );
this->SetTopWindow( frame );
frame->Show();
return true;
}
void wxTestProject::OnChange( wxStyledTextEvent& event )
{
wxStyledTextCtrl* stc = (wxStyledTextCtrl*)event.GetEventObject();
// Find the word start
int currentPos = stc->GetCurrentPos();
int wordStartPos = stc->WordStartPosition( currentPos, true );
// Display the autocompletion list
int lenEntered = currentPos - wordStartPos;
if (lenEntered > 0)
{
stc->AutoCompShow(lenEntered, "and break do else elseif end false for function if in local nil not or repeat return then true until while");
}
}

Related

Intellij intention 'Creates missing switch branches' not working

Intellij's 'Creates missing switch branches' intention seems not to be working for me. I have enabled/disabled/enabled it with restarts of intellij, but I never get the alt-enter possibility to create a completed switch statement.
Am I missing something? I'm working with the latest version of intellij ultimate.
Here's an example that works :
class SwitchBranches {
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;
void x(#MagicConstant(intValues = {ONE, TWO, THREE}) int i) {
switch (i) { // position the text caret on the `i` expression or on the switch keyword
}
}
}
If you need this functionality to create a switch statement for enum values, use the Enum 'switch' statement that misses case inspection. It is enabled by default at the "No highlighting, only fix" level. Example:
enum EnumExample {
A, B, C;
void x(EnumExample e) {
switch (e) {
}
}
}

Change the backcolor of current line of caret position [duplicate]

I have uploaded a image of what i want to achive...
So as you can see i want to highlight the line i click on [And update it on _textchanged event!
Is there any possible way of doing this in any colour... doesnt have to be yellow. I have searched alot but i cant understand how to get the starting length and end length and all of that.
It has confused me alot and i don;'t understand and would require some help.
Thanks for all help that is given in this thread. Also it is windows form. Im making a notepad app like notepad++ or some other notepad app... .NET Windows Form C# RichTextBox
You'll need to create your own control that inherits from RichTextBox and use that control on your form. Since the RichTextBox does not support owner drawing, you will have to listen for the WM_PAINT message and then do your work in there. Here is an example that works fairly well, though the line height is hard coded right now:
public class HighlightableRTB : RichTextBox
{
// You should probably find a way to calculate this, as each line could have a different height.
private int LineHeight = 15;
public HighlightableRTB()
{
HighlightColor = Color.Yellow;
}
[Category("Custom"),
Description("Specifies the highlight color.")]
public Color HighlightColor { get; set; }
protected override void OnSelectionChanged(EventArgs e)
{
base.OnSelectionChanged(e);
this.Invalidate();
}
private const int WM_PAINT = 15;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PAINT)
{
var selectLength = this.SelectionLength;
var selectStart = this.SelectionStart;
this.Invalidate();
base.WndProc(ref m);
if (selectLength > 0) return; // Hides the highlight if the user is selecting something
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
Brush b = new SolidBrush(Color.FromArgb(50, HighlightColor));
var line = this.GetLineFromCharIndex(selectStart);
var loc = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(line));
g.FillRectangle(b, new Rectangle(loc, new Size(this.Width, LineHeight)));
}
}
else
{
base.WndProc(ref m);
}
}
}

Using a Prism PubSub style event in C++/CLI

I'm trying to create an event aggregator in C++/CLI, I know that the valid syntax in C# would be as follows:
//C# code
public partial class Foo : UserControl, IView, IDisposable
{
private IEventAggregator _aggregator;
public Foo(IEventAggregator aggregator)
{
InitializeComponent();
this._aggregator = aggregator;
if (this._aggregator == null)
throw new Exception("null pointer");
_subToken =_aggregator.GetEvent<fooEvent>().Subscribe(Handler, ThreadOption.UIThread, false);
}
private SubscriptionToken _subToken = null;
private void Handler(fooEventPayload args)
{
//this gets run on the event
}
}
However directly converting this to C++/CLI gives the error "a pointer-to-member is not valid for a managed class" on the indicated line. Is there a workaround? I think it has something to do with how C# generates "Action".
//C++/CLI code
ref class Foo
{
public:
Foo(IEventAggregator^ aggregator)
{
void InitializeComponent();
this->_aggregator = aggregator;
if (this->_aggregator == nullptr)
throw gcnew Exception("null pointer");
//error in the following line on Hander, a pointer-to-member is not valid for a managed class
_subToken = _aggregator->GetEvent<fooEvent^>()->Subscribe(Handler, ThreadOption::UIThread, false);
private:
IEventAggregator ^ _aggregator;
SubscriptionToken ^ _addActorPipelineToken = nullptr;
void Handler(fooEventPayload^ args)
{
//this gets run on the event
}
}
You need to explicitly instantiate the delegate object, rather than allowing C# to do this for you.
_subToken = _aggregator->GetEvent<fooEvent^>()->Subscribe(
gcnew Action<fooEventPayload^>(this, &Foo::Handler), ThreadOption::UIThread, false);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Explicitly instantiate the delegate.
// ^^^^ Object to call the delegate on.
// ^^^^^^^^^^^^^ C++-style reference to the method.

How to display a Labels 'Error on ErrorProvider1'

Goal
I want to display the text that I put in the Label's "Error on ErrorProvider1" attribute whenever I get an error. See the following label's attributes below.
I try to display the text in the red rectangle into my ErrorProvider1 SetError(control, value) function.
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, ErrorProvider1.GetError(lblErr))
Else
ErrorProvider1.SetError(lblErr, "")
End If
How can I retrieve the 'Error on ErrorProvider1' text from the lblErr to display it in the ErrorProvider1 SetError value?
The ErrorProvider component is very awkward to use effectively. It is fixable however, I'll give an example in C# that extends the component with some new capabilities:
ShowError(Control ctl, bool enable) displays the text that you entered at design-time when the enable argument is true. The easier-to-use version of SetError().
HasErrors returns true if the any active warning icons are displayed. Handy in your OK button's Click event handler.
FocusError() sets the focus to the first control that has a warning icon, if any. It returns false if no warnings are remaining.
SetError() is a replacement of ErrorProvider.SetError(). You only need it if you add any controls after the form's Load event fired or if you need to modify the warning text.
Add a new class to your project and paste the code shown below. Compile. Drop it from the top of the toolbox onto the form. The design-time behavior is identical. Modestly tested.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
class MyErrorProvider : ErrorProvider {
public void ShowError(Control ctl, bool enable) {
// Easy to use version of SetError(), uses design-time text
if (!enable) base.SetError(ctl, "");
else {
if (errors.ContainsKey(ctl)) base.SetError(ctl, errors[ctl]);
else base.SetError(ctl, "No error text available");
}
}
public bool HasErrors {
// True if any errors are present
get {
foreach (var err in errors)
if (!string.IsNullOrEmpty(base.GetError(err.Key))) return true;
return false;
}
}
public bool FocusError() {
// Set the focus to the first control with an active error
foreach (var err in errors) {
if (!string.IsNullOrEmpty(base.GetError(err.Key))) {
err.Key.Focus();
return true;
}
}
return false;
}
public new void SetError(Control ctl, string text) {
// Use this only to add/modify error text after the form's Load event
if (!string.IsNullOrEmpty(text)) {
if (errors.ContainsKey(ctl)) errors[ctl] = text;
else errors.Add(ctl, text);
}
base.SetError(ctl, text);
}
private void initialize(object sender, EventArgs e) {
// Preserve error text
copyErrors(((Form)sender).Controls);
}
private void copyErrors(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
var text = this.GetError(ctl);
if (!string.IsNullOrEmpty(text)) {
errors.Add(ctl, text);
base.SetError(ctl, "");
}
copyErrors(ctl.Controls);
}
}
private Dictionary<Control, string> errors = new Dictionary<Control, string>();
// Plumbing to hook the form's Load event
[Browsable(false)]
public new ContainerControl ContainerControl {
get { return base.ContainerControl; }
set {
if (base.ContainerControl == null) {
var form = value.FindForm();
if (form != null) form.Load += initialize;
}
base.ContainerControl = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
}
Your issue is that you are replacing the error message when nothing is wrong. As noted in your comment below, you are storing the localized error message in the label's Tag, so you can do the following:
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, lblErr.Tag)
Else
ErrorProvider1.SetError(lblErr, "")
End If
You were correct to use ErrorProvider1.GetError(Control) to get the value. It's just that you're more than likely replacing it with an empty string before you were retrieving it.

Mono.CSharp: how do I inject a value/entity *into* a script?

Just came across the latest build of Mono.CSharp and love the promise it offers.
Was able to get the following all worked out:
namespace XAct.Spikes.Duo
{
class Program
{
static void Main(string[] args)
{
CompilerSettings compilerSettings = new CompilerSettings();
compilerSettings.LoadDefaultReferences = true;
Report report = new Report(new Mono.CSharp.ConsoleReportPrinter());
Mono.CSharp.Evaluator e;
e= new Evaluator(compilerSettings, report);
//IMPORTANT:This has to be put before you include references to any assemblies
//our you;ll get a stream of errors:
e.Run("using System;");
//IMPORTANT:You have to reference the assemblies your code references...
//...including this one:
e.Run("using XAct.Spikes.Duo;");
//Go crazy -- although that takes time:
//foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
//{
// e.ReferenceAssembly(assembly);
//}
//More appropriate in most cases:
e.ReferenceAssembly((typeof(A).Assembly));
//Exception due to no semicolon
//e.Run("var a = 1+3");
//Doesn't set anything:
//e.Run("a = 1+3;");
//Works:
//e.ReferenceAssembly(typeof(A).Assembly);
e.Run("var a = 1+3;");
e.Run("A x = new A{Name=\"Joe\"};");
var a = e.Evaluate("a;");
var x = e.Evaluate("x;");
//Not extremely useful:
string check = e.GetVars();
//Note that you have to type it:
Console.WriteLine(((A) x).Name);
e = new Evaluator(compilerSettings, report);
var b = e.Evaluate("a;");
}
}
public class A
{
public string Name { get; set; }
}
}
And that was fun...can create a variable in the script's scope, and export the value.
There's just one last thing to figure out... how can I get a value in (eg, a domain entity that I want to apply a Rule script on), without using a static (am thinking of using this in a web app)?
I've seen the use compiled delegates -- but that was for the previous version of Mono.CSharp, and it doesn't seem to work any longer.
Anybody have a suggestion on how to do this with the current version?
Thanks very much.
References:
* Injecting a variable into the Mono.CSharp.Evaluator (runtime compiling a LINQ query from string)
* http://naveensrinivasan.com/tag/mono/
I know it's almost 9 years later, but I think I found a viable solution to inject local variables. It is using a static variable but can still be used by multiple evaluators without collision.
You can use a static Dictionary<string, object> which holds the reference to be injected. Let's say we are doing all this from within our class CsharpConsole:
public class CsharpConsole {
public static Dictionary<string, object> InjectionRepository {get; set; } = new Dictionary<string, object>();
}
The idea is to temporarily place the value in there with a GUID as key so there won't be any conflict between multiple evaluator instances. To inject do this:
public void InjectLocal(string name, object value, string type=null) {
var id = Guid.NewGuid().ToString();
InjectionRepository[id] = value;
type = type ?? value.GetType().FullName;
// note for generic or nested types value.GetType().FullName won't return a compilable type string, so you have to set the type parameter manually
var success = _evaluator.Run($"var {name} = ({type})MyNamespace.CsharpConsole.InjectionRepository[\"{id}\"];");
// clean it up to avoid memory leak
InjectionRepository.Remove(id);
}
Also for accessing local variables there is a workaround using Reflection so you can have a nice [] accessor with get and set:
public object this[string variable]
{
get
{
FieldInfo fieldInfo = typeof(Evaluator).GetField("fields", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
var fields = fieldInfo.GetValue(_evaluator) as Dictionary<string, Tuple<FieldSpec, FieldInfo>>;
if (fields != null)
{
if (fields.TryGetValue(variable, out var tuple) && tuple != null)
{
var value = tuple.Item2.GetValue(_evaluator);
return value;
}
}
}
return null;
}
set
{
InjectLocal(variable, value);
}
}
Using this trick, you can even inject delegates and functions that your evaluated code can call from within the script. For instance, I inject a print function which my code can call to ouput something to the gui console window:
public delegate void PrintFunc(params object[] o);
public void puts(params object[] o)
{
// call the OnPrint event to redirect the output to gui console
if (OnPrint!=null)
OnPrint(string.Join("", o.Select(x => (x ?? "null").ToString() + "\n").ToArray()));
}
This puts function can now be easily injected like this:
InjectLocal("puts", (PrintFunc)puts, "CsInterpreter2.PrintFunc");
And just be called from within your scripts:
puts(new object[] { "hello", "world!" });
Note, there is also a native function print but it directly writes to STDOUT and redirecting individual output from multiple console windows is not possible.