FarNet - .NET Far API and .NET plugin manager (English)

Here you can discuss about your favorite plug-in.
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

Latest post of the previous page:

senpost
I am not trying to stop you. But where did you see such a UI in Far? FarNet cannot do something that Far or plugins do not do (in UI, at least).
User avatar
senpost
Posts: 53
Joined: Fri 27 Mar, 2009 03:54

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by senpost »

No, I don't think you are trying to stop me, I am just curious if FAR allows these kind of customization.
"To us all towns are one, all men our kin"
Kanniyan Poongundran, Tamil Poet, 500 BC
User avatar
senpost
Posts: 53
Joined: Fri 27 Mar, 2009 03:54

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by senpost »

Different question :) How can I execute commands like viewer:somefile or macro: post F11 from a FarNet module?
"To us all towns are one, all men our kin"
Kanniyan Poongundran, Tamil Poet, 500 BC
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

Do you read the API docs?

1) Far.Net.CreateViewer(); then see IViewer members in the docs.
2) Far.Net.PostMacro() or other Post* methods, see the docs again.

If you do not like/can read the API help then take module sources (there are a few modules there) and learn the sources.
User avatar
senpost
Posts: 53
Joined: Fri 27 Mar, 2009 03:54

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by senpost »

I do read API doc, I muct have missed the Post* APIs. Sorry I should have been more clear on what I was asking, rather than using different API to run different things, can send these commands to FAR to execute it from a FarNet module? I tried Far.Net.PostText it just places the text in the command line it doesn't execute it.
"To us all towns are one, all men our kin"
Kanniyan Poongundran, Tamil Poet, 500 BC
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

I tried Far.Net.PostText it just places the text in the command line it doesn't execute it.
What was the text posted? Did you "type" "Enter" in the end?
User avatar
senpost
Posts: 53
Joined: Fri 27 Mar, 2009 03:54

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by senpost »

Code: Select all

Far.Net.PostText("viewer:a.txt", true); //This doesnt work
Far.Net.PostText("viewer:a.txt" + Environment.NewLine, true); //This works
Thanks
"To us all towns are one, all men our kin"
Kanniyan Poongundran, Tamil Poet, 500 BC
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

This should work, too (with "\n"):
Far.Net.PostText("viewer:a.txt\n", true);
vzell
Posts: 2
Joined: Sat 04 Feb, 2012 20:50

System.ArgumentOutOfRangeException when editing a file

Post by vzell »

I get the following error with Far 3.0 build 4040 and 4042 x64 whenever trying to edit a file

╔══════════════════════════ System.ArgumentOutOfRangeException ══════════════════════════╗
║ Index was out of range. Must be non-negative and less than the size of the collection. ║
║ Parameter name: index ║
╟────────────────────────────────── ────────────────────────────────────────────╢
║ { Ok } [ More ] ║
╚══════════════════════════════════════════════════════════════════════════════╝
vzell
Posts: 2
Joined: Sat 04 Feb, 2012 20:50

Re: System.ArgumentOutOfRangeException when editing a file

Post by vzell »

and the following message after pressing MORE button:

ArgumentOutOfRangeException:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.Generic.List`1.get_Item(Int32 index)
at FarNet.Editor0.AsProcessEditorEvent(ProcessEditorEventInfo* info)
at ProcessEditorEventW(ProcessEditorEventInfo* info)
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

Re: FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

Old FarNet?
elize
Posts: 6
Joined: Tue 28 Oct, 2014 19:21

FarNet - .NET Far API and .NET plugin manager (English)

Post by elize »

Privet \ Hello,

Thanks a lot for great FarNet library!!!

I just upgraded from FarNet 5.0.32 to latest one 5.0.59 in order to support latest versions of Far > 4159.
In previous version of FarNet my custom editor\viewer worked just fine.

For simplicity you can think of it as a viewer of files encoded in base64 format.
The logic of my custom editor (viewer) is all in Invoke() method and aux static functions (see snippet code below).
Basically:
* Ask user if he \ she wants to convert the file, open as it or Cancel the operation, here I'm using Far.Api.Message() function
* If Yes convert the file by creating *NEW* file in %TEMP% folder
* Close current editor by calling editor.Close()
* Open *NEW* file by calling:
IEditor editor = Far.Api.CreateEditor();
editor.Title = Path.GetFileName(filename);
editor.FileName = filename;
editor.DeleteSource = DeleteSource.File;
editor.Open();
* If user want to open as is just continue without any conversation
* If cancel call editor.Close()

In 5.0.32 and Far 38xx (both x86 and x64) the above code worked just perfect.

Now, I'm having the following issue with new FarNet 5.0.59 and Far 4160 x64 (see image below):
* Far.Api.Message() for some reason causes editor Invoke() to be called *AGAIN* (on the same thread), here callstack:
> Sha.dll!Sha.Base64Editor.Invoke(object sender, FarNet.ModuleEditorEventArgs e) Line 21 C#
[External Code]
Sha.dll!Sha.Base64Editor.Invoke(object sender, FarNet.ModuleEditorEventArgs e) Line 21 C#
[External Code]
Line 21 is Far.Api.Message()


Below please find sample code which you can compile and deploy to repro the problem:
* Set a breakpoint on Far.Api.Message() and hit F10

Thanks a lot for your help,
Eli (Илья) Zeitlin from Microsoft
TwoMessageBoxes.PNG
TwoMessageBoxes.PNG (31.2 KiB) Viewed 12433 times

Code: Select all

using FarNet;
using FarNet.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Sha
{

    [System.Runtime.InteropServices.Guid("53CD6F79-51A9-4D61-80D9-38ABF266F965")]
    [ModuleEditor(Name = "Base64 Editor", Mask = "*.base64*")]
    public class Base64Editor : ModuleEditor
    {
        // Redirect F4 on .base64_* file to our editor
        public override void Invoke(object sender, ModuleEditorEventArgs e)
        {
            var editor = (IEditor)sender;

            switch (Far.Api.Message(string.Format(
                           "Do you want to convert base64 file?\n",
                            Path.GetFileName(editor.FileName)), "Base64 Editor", MessageOptions.None, new string[] { "Yes", "Open as is", "Cancel" }))
            {
                case 0: // Convert
                    editor.Close();
                    OpenTempFileInEditor(ConvertBase64BondFileToBinaryBondFile(editor.FileName));
                    return;
                case 1: // Open as is
                    break;
                default: // ESC
                    editor.Close();
                    break;
            }
        }

        public static void OpenTempFileInEditor(string filename)
        {
            if (IsFileExistAndNotEmpty(filename))
            {
                IEditor editor = Far.Api.CreateEditor();
                editor.Title = Path.GetFileName(filename);
                editor.FileName = filename;
                editor.DeleteSource = DeleteSource.File;
                editor.Open();
            }
        }

        //  Show progress box during conversion opeartions
        private static void UpdateProgress(ProgressBox pb, TimeSpan refreshRate, string srcFile, string destFile, long entityIndex, long completed, long size)
        {
            if (pb.ElapsedFromShow > refreshRate)
            {
                pb.Activity = string.Format("From: {0}\nTo: {1}\nEntities: {2}", srcFile, destFile, entityIndex);
                if (size > 0) pb.SetProgressValue(completed, size);
                pb.ShowProgress();
            }
        }

        /// <summary>
        /// This function will convert *.base64 format file to %TEMP%\*.base64.bond file
        /// It will delete the source *.base64 file if is located under %TEMP% folder on success
        /// </summary>
        /// <param name="filename">Full path to *.base64 file</param>
        /// <returns>Full path to generated .bond file</returns>
        private static string ConvertBase64BondFileToBinaryBondFile(string filename)
        {
            TimeSpan refreshRate = TimeSpan.FromMilliseconds(50); // 20 times in 1 sec
            string tempBondFilename = Path.Combine(Path.GetTempPath(), Path.GetFileName(filename) + ".bond");
            long entityIndex = 0;
            var pb = new ProgressBox("Converting base64 Bond to binary Bond") { LineCount = 4 };
            UpdateProgress(pb, refreshRate, filename, tempBondFilename, entityIndex, 0, 0);
            try
            {
                using (var fsIn = new FileStream(filename, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
                {
                    var reader = new StreamReader(fsIn);
                    using (var fsOut = new FileStream(tempBondFilename, FileMode.Create))
                    {
                        while (!reader.EndOfStream)
                        {
                            var line = reader.ReadLine();
                            entityIndex++;
                            UpdateProgress(pb, refreshRate, filename, tempBondFilename, entityIndex, fsIn.Position, fsIn.Length);
                            try
                            {
                                var entityByte = Convert.FromBase64String(line);
                                fsOut.Write(entityByte, 0, entityByte.Length);
                            }
                            catch (FormatException) // Skip errors for first and last lines. Example first line in last 1 mb from file or last line in first 1 mb from file
                            {
                                if ((entityIndex > 1) && (!reader.EndOfStream))
                                {
                                    throw;
                                }
                            }
                            if (UIUserStop())
                            {
                                break;
                            }
                        }
                    }
                }
                // .bond file is under %TEMP%  let's delete it
                if (filename.StartsWith(Path.GetTempPath(), StringComparison.CurrentCultureIgnoreCase))
                {
                    File.Delete(filename);
                }
            }
            catch (Exception e)
            {
                if (IsFileExistAndNotEmpty(tempBondFilename))
                {
                    Far.Api.ShowError("Conversion of base64 Bond to binary Bond failed", e);
                }
            }
            pb.Dispose();
            Far.Api.UI.Redraw();
            return tempBondFilename;
        }

        /// <summary>
        /// Returns True if ESC was pressed, otherwise False
        /// </summary>
        /// <returns>Returns True if ESC was pressed, otherwise False</returns>
        public static bool UIUserStop()
        {
            if ((Console.KeyAvailable) && (Console.ReadKey().Key == ConsoleKey.Escape))
            {
                return (0 == Far.Api.Message("Are you sure you want to cancel this operation?", "", MessageOptions.YesNo));
            }
            return false;
        }

        public static bool IsFileExistAndNotEmpty(string filename)
        {
            return (File.Exists(filename) && (new FileInfo(filename).Length > 0));
        }
    }
}

User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

elize
I'll take a look soon. Meantime I recommend to get Far 3.0.4162. Just to be sure that you are with the most recent version.
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

It is because in Far now EE_GOTFOCUS happens before EE_READ. This may look unexpected but such is the design. FarNet is partially adapted for this but not completely, apparently. As a result, the initialization procedure (Invoke()) is called twice on both events. I'll think how to fix this. Thank you for reporting this yet missed problem case.
User avatar
NightRoman
Posts: 6184
Joined: Fri 18 Aug, 2006 13:52
Location: Cambridge, UK
Has thanked: 32 times
Been thanked: 62 times
Contact:

FarNet - .NET Far API and .NET plugin manager (English)

Post by NightRoman »

And another problem is yours in the mask and the way you create a temp file

Code: Select all

[ModuleEditor(Name = "Base64 Editor", Mask = "*.base64*")]
When you create a temp file you just append ".bond" to the name. But this new file (*.base64*.bond) still matches the mask "*.base64*", so that Invoke() is called again for this file. You should either change a mask, i.e. "*.base64" (i.e. extension is exactly base64) or ensure that a temp file name does not contain ".base64" in it.
elize
Posts: 6
Joined: Tue 28 Oct, 2014 19:21

FarNet - .NET Far API and .NET plugin manager (English)

Post by elize »

The mask is actually correct, I didn't paste all the code :-)
There is another conversion which happen from .bond to .json

I will try 4162 tomorrow, very doubt it will fix the twice Invoke() issue.
So Far.Api.Message() somehow changes the focus and this causes double Invoke()? Or even without Far.Api.Message() one will get twice Invoke()?
Post Reply

Return to “General Plug-In Discussions”