/// <summary>
        /// JavaScript callback. Returns absolute path to the file that is referenced from the file in the
        /// editor. Implementation copied from the Emmet project source code.
        /// </summary>
        public InternalHandle LocateFile(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length != 2)
            {
                this.TraceError("IEmmetFile locateFile called with invalid number of arguments.");
                return engine.CreateValue(false);
            }

            string editorFile = args[0].AsString;
            string targetFile = args[1].AsString;

            if (targetFile.StartsWith("HTTP", System.StringComparison.InvariantCultureIgnoreCase))
                return engine.CreateValue(targetFile);

            string folder = Path.GetDirectoryName(editorFile);
            do
            {
                string retVal = Path.Combine(folder, targetFile);
                if (File.Exists(retVal))
                    return engine.CreateValue(retVal);
            }
            while (folder.Length > 3);

            return engine.CreateValue(string.Empty);
        }
        /// <summary>
        /// JavaScript callback. Returns character indexes of selected text: object with <code>start</code>
        /// and <code>end</code> properties.If there's no selection, should return object with
        /// <code>start</code> and <code>end</code> properties referring to current caret position.
        /// </summary>
        public InternalHandle GetSelectionRange(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            var selection = _editor.GetSelectionRange();
            ObjectHandle retVal = engine.CreateObject();
            retVal.SetProperty("start", engine.CreateValue(selection.Start));
            retVal.SetProperty("end", engine.CreateValue(selection.End));

            return retVal;
        }
Example #3
0
        // --------------------------------------------------------------------------------------------------------------------

        public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
        {
            if (!_Handle.IsObjectType)
            {
                throw new InvalidOperationException(InternalHandle._NOT_AN_OBJECT_ERRORMSG);
            }

            var isHandleBase = typeof(IHandleBased).IsAssignableFrom(value.RuntimeType);

            Expression[] args = new Expression[isHandleBase ? 3 : 5];
            MethodInfo   methodInfo;

            // ... create parameters for the call expression to set a value given a property name ...

            args[0] = Expression.Constant(binder.Name);

            if (isHandleBase) // (if the interface is implemented, then we need a converter to detect and pull out the handle value)
            {
                Func <object, InternalHandle> handleParamConversion
                    = obj => (obj is IHandleBased) ? ((IHandleBased)obj).InternalHandle
                        : _Engine != null?_Engine.CreateValue(obj)
                          : InternalHandle.Empty;

                var convertParameter = Expression.Call(
                    Expression.Constant(handleParamConversion.Target),
                    handleParamConversion.Method,
                    Expression.Convert(value.Expression, typeof(object)));

                args[1] = convertParameter;
                args[2] = Expression.Constant(V8PropertyAttributes.None);

                methodInfo = ((Func <string, InternalHandle, V8PropertyAttributes, bool>)_Handle.SetProperty).Method;
            }
            else // (no interface is implemented, so default to just 'object')
            {
                args[1]    = Expression.Convert(value.Expression, typeof(object));
                args[2]    = Expression.Constant(null, typeof(string));
                args[3]    = Expression.Constant(null, typeof(bool?));
                args[4]    = Expression.Constant(null, typeof(ScriptMemberSecurity?));
                methodInfo = ((Func <string, object, string, bool?, ScriptMemberSecurity?, bool>)_Handle.SetProperty).Method;
            }

            Func <object, InternalHandle> conversionDelegate = _GetInternalHandleFromObject;
            var self = Expression.Convert(Expression, typeof(InternalHandle), conversionDelegate.Method);

            var methodCall = Expression.Call(self, methodInfo, args);

            BindingRestrictions restrictions = Restrictions.Merge(value.Restrictions);

            return(new DynamicMetaObject(Expression.Convert(methodCall, binder.ReturnType), restrictions));
        }
        /// <summary>
        /// Looks for tab stops in the specified content and returns a processed version with expanded
        /// placeholders and tab stops found.
        /// </summary>
        /// <param name="engine">V8 instance with Emmet engine compiled in it.</param>
        /// <param name="content">Expanded abbreviation content.</param>
        /// <exception cref="Exception{EmmetEngineExceptionArgs}">
        /// Indicates that Emmet engine has failed to parse the specified content.
        /// </exception>
        public static TabStopsParser ParseContent(V8Engine engine, string content)
        {
            ObjectHandle tabStopsUtil = engine.DynamicGlobalObject.window.emmet.tabStops;
            Handle extractResult = tabStopsUtil.Call("extract", null, engine.CreateValue(content));

            if (extractResult.IsError)
            {
                var ex = new EmmetEngineExceptionArgs(
                    "Error while trying to extract tab stops.",
                    extractResult);
                throw new Exception<EmmetEngineExceptionArgs>(ex);
            }

            TabStopsParser retVal = new TabStopsParser();
            ObjectHandle tabStopsObj = (ObjectHandle)extractResult;
            retVal.Content = tabStopsObj.GetProperty(@"text").AsString;
            ObjectHandle tabStopsList = tabStopsObj.GetProperty(@"tabstops");

            // Tab stops should be added before modifying document so that editor can track their position.
            int tabStopsCount = tabStopsList.ArrayLength;

            if (tabStopsCount > 0)
            {
                retVal.TabStops = new Range[tabStopsCount];
                retVal.TabStopGroups = new int[tabStopsCount];

                for (int i = 0; i < tabStopsCount; i++)
                {
                    ObjectHandle tabStopObj = tabStopsList.GetProperty(i.ToString());
                    int start = tabStopObj.GetProperty("start").AsInt32;
                    int end = tabStopObj.GetProperty("end").AsInt32;
                    int group = tabStopObj.GetProperty("group").AsInt32;

                    retVal.TabStops[i] = new Range(start, end);
                    retVal.TabStopGroups[i] = group;
                }
            }

            return retVal;
        }
        /// <summary>
        /// JavaScript callback. Reads the specified file content and returns it as string.
        /// </summary>
        public InternalHandle Read(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length != 3)
            {
                this.TraceError("IEmmetFile read called with invalid number of arguments.");
                return engine.CreateValue(false);
            }

            string targetFilePath = args[0].AsString;
            int chunkSize = args[1].AsInt32;
            ObjectHandle callback = args[2];

            if (!File.Exists(targetFilePath))
            {
                this.TraceError($"Emmet requested file {targetFilePath} that does not exist.");
                callback.StaticCall(engine.CreateValue(true), engine.CreateNullValue());

                return engine.CreateValue(false);
            }

            char[] buf = new char[chunkSize];
            FileStream stream = File.OpenRead(targetFilePath);
            using (StreamReader reader = new StreamReader(stream))
            {
                chunkSize = reader.ReadBlock(buf, 0, chunkSize);
            }

            string retVal = new string(buf, 0, chunkSize);
            callback.StaticCall(engine.CreateValue(false), engine.CreateValue(retVal));

            return engine.CreateValue(true);
        }
        /// <summary>
        /// JavaScript callback. Creates selection from <code>start</code> to <code>end</code> character
        /// indexes. If <code>end</code> is omitted, this method should place caret and <code>start</code>
        /// index.
        /// </summary>
        public InternalHandle CreateSelection(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length == 2)
            {
                int start = args[0].AsInt32;
                int end = args[0].AsInt32;
                _editor.CreateSelection(start, end);
            }
            else
            {
                return SetCarretPos(engine, isConstructCall, self, args);
            }

            return engine.CreateValue(true);
        }
        /// <summary>
        /// JavaScript callback. Returns current selection.
        /// </summary>
        public InternalHandle GetSelection(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            string selection = _editor.GetSelection();
            if (string.IsNullOrEmpty(selection))
                return engine.CreateValue(string.Empty);

            return engine.CreateValue(selection);
        }
        /// <summary>
        /// JavaScript callback. Asks user to enter something.
        /// </summary>
        public InternalHandle Prompt(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            string input = _editor.Prompt();
            if (string.IsNullOrWhiteSpace(input))
                return engine.CreateNullValue();

            return engine.CreateValue(input);
        }
 /// <summary>
 /// JavaScript callback. Returns current editor's syntax mode.
 /// </summary>
 public InternalHandle GetSyntax(
     V8Engine engine,
     bool isConstructCall,
     InternalHandle self,
     params InternalHandle[] args)
 {
     return engine.CreateValue(_syntax);
 }
 /// <summary>
 /// JavaScript callbacks. Returns the content of the current editor window.
 /// </summary>
 public InternalHandle GetContent(
     V8Engine engine,
     bool isConstructCall,
     InternalHandle self,
     params InternalHandle[] args)
 {
     return engine.CreateValue(_editor.GetContent());
 }
        /// <summary>
        /// JavaScript callback. Returns file extension in lower case.
        /// </summary>
        public InternalHandle GetExtension(
            V8Engine engine,
            bool isConstructorCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length != 1)
            {
                this.TraceError("IEmmetFile getExt called with invalid number of arguments.");
                return engine.CreateValue(false);
            }

            string filePath = args[0].AsString;

            return engine.CreateValue(Path.GetExtension(filePath).ToLowerInvariant());
        }
        /// <summary>
        /// JavaScript callback. Returns the content of the current line.
        /// </summary>
        public InternalHandle GetCurrentLine(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            string txt = _editor.GetCurrentLine();

            return engine.CreateValue(txt);
        }
        /// <summary>
        /// JavaScript callback. Set new caret position.
        /// </summary>
        public InternalHandle SetCarretPos(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            _editor.SetCaretPosition(args[0].AsInt32);

            return engine.CreateValue(true);
        }
        /// <summary>
        /// JavaScript callback. Creates absolute path by concatenating two arguments.
        /// </summary>
        public InternalHandle CreatePath(
            V8Engine engine,
            bool isConstructorCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length != 2)
            {
                this.TraceError("IEmmetFile createPath called with invalid number of arguments.");
                return engine.CreateValue(false);
            }

            string parent = args[0].AsString;
            string fileName = args[1].AsString;

            if (Path.HasExtension(parent))
                parent = Path.GetDirectoryName(parent);

            return engine.CreateValue(Path.Combine(parent, fileName));
        }
Example #15
0
 public JSProperty(V8Engine engine, object value, V8PropertyAttributes attributes = V8PropertyAttributes.None)
     : this(InternalHandle.Empty, attributes)
 {
     _Value.Set(engine != null ? engine.CreateValue(value) : InternalHandle.Empty);
 }
        /// <summary>
        /// JavaScript callback. Replace editor's content or it's part (from <code>start</code> to
        /// <code>end</code> index). If <code>value</code> contains <code>caret_placeholder</code>, the editor
        /// will put caret into this position. If you skip <code>start</code> and <code>end</code> arguments,
        /// the whole target's content will be replaced with <code>value</code>.
        /// If you pass <code>start</code> argument only, the <code>value</code> will be placed at
        /// <code>start</code> string index of current content.
        /// If you pass <code>start</code> and <code>end</code> arguments, the corresponding substring of
        /// current target's content will be replaced with <code>value</code>.
        /// </summary>
        public InternalHandle ReplaceContent(
            V8Engine engine,
            bool isConstructCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            string rawContent = args[0].AsString;
            int regionStart = args.Length > 1 ? args[1].AsInt32 : -1;
            int regionLength = args.Length > 2 ? args[2].AsInt32 - regionStart : 0;
            bool indentContent = args.Length == 4 ? args[3].AsBoolean : true;

            this.Trace($"Received new content for the editor: {rawContent}");

            // Extract tab stops placeholders from the specified content.
            var tabStops = TabStopsParser.ParseContent(engine, rawContent);

            _editor.ReplaceContentRange(tabStops.Content, regionStart, regionStart + regionLength);

            if (null != tabStops.TabStops)
            {
                Range[] tabStopRanges = tabStops.TabStops;

                // Tab stop offsets are relative to the newly generated content ranges, we need to convert
                // them to the document-wide offsets.
                if (regionStart > 0)
                {
                    tabStopRanges = tabStopRanges.Select(
                        item => new Range(item.Start + regionStart, item.End + regionStart)).ToArray();
                }

                _editor.TrackTabStops(tabStopRanges, tabStops.TabStopGroups);
            }

            if (indentContent)
                _editor.FormatRegion(regionStart, regionStart + tabStops.Content.Length);

            return engine.CreateValue(true);
        }
        /// <summary>
        /// JavaScript callback. Saves the specified content to the file with the specified name.
        /// </summary>
        public InternalHandle Save(
            V8Engine engine,
            bool isConstructorCall,
            InternalHandle self,
            params InternalHandle[] args)
        {
            if (args.Length != 2)
            {
                this.TraceError("IEmmetFile save called with invalid number of arguments.");
                return engine.CreateValue(false);
            }

            string filePath = args[0].AsString;
            string content = args[1].AsString;

            File.WriteAllText(filePath, content);

            return engine.CreateValue(true);
        }