Visual Studio extension code completion- multiple file data - visual-studio-2012

I'm looking to create code completion for a custom language in Visual Studio. I already have code for some simpler editor interaction, like syntax highlighting and brace matching. Now I want to move to code completion. But I've run into a slight problem- data sources.
Like in a language such as C#, I implicitly share code between more than one file. This implies that, in order to code complete one file, I need to know the contents of the other files. More specifically, whilst I could simply iterate through the project and project items and crack open the files, this is a suboptimal solution. For example, I wouldn't be able to code complete unsaved changes the user has made. For another, I already did a lot of processing work lexing or parsing the contents to fill the user's request for syntax highlighting and whatnot, and I have no desire to duplicate that work.
How can I access the contents of the other files in the project, and obtain their ITextBuffers so I can re-use the work I already did?

There is no ITextBuffer provided for files which exist on disk but are not currently open in Visual Studio. It is possible to create an instance of ITextBuffer for any arbitrary file by using ITextDocumentFactoryService::CreateAndLoadDocument. This takes a string and will give back an ITextDocument instance from which you can access an ITextBuffer.
In order to find the existing ITextBuffer for files that are currently open you can do the following
IVsRunningDocumentTable::FindDocument This takes a file path and returns a cookie representing that file if it is currently open (Example)
IVsRunningDocumentTable::GetDocumentInfo This takes a cookie and returns back an IVsTextLines instance (Example)
IVsEditorAdaptersFactoryService::GetDataBuffer takes an IVsTextLines and gives back an ITextBuffer (Example)

Related

Excel behaves strange with XSLX file created manually

Based on knowledge gained through working with the OpenXML SDK, I have implemented an Excel generator in JS (using TypeScript with ReactJS and a custom JSX factory generating plain XML). The files generated open fine in Excel and one can also edit and save them fine in Excel, no errors.
However, if one tries to copy cells (even a single one) from such a generated Excel file to another worksheet in the same Excel instance, it fails with the error "The command cannot be used on multiple selections.". Just saving and reopening the file is enough to fix the problem. Copying to other applications (e.g. Notepad) works fine.
It seems that this particular error is shown by Excel in several edge cases where the data is not exactly meet the expected format, for instance I found reports of that happening when a sheet is hidden when manipulating it via VBA. However, in my case I'm not sure what could be causing the issue.
Just saving the file in Excel unfortunately significantly alters its parts, so that I couldn't get a meaningful diff out of it. I did not see what could be causing the problem. Maybe someone has some experience with the internals of Excel?
To get a sample file, copy the following into your browser address bar and save it as xlsx file:
data:application/vndopenxmlformats-officedocumentspreadsheetmlsheet;base64,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
Well, I don't know the particulars of how you are generating the xml file, but I can tell you how to edit the underlying xml files so that it will work, and then perhaps you can figure out how to use your implementation to change the property that's gunking things up.
First, an xlsx is a set of xml files. I'm sure you know that, but I'm just starting at the beginning. You can change the extension to zip and then extract the files, and then rezip them and change the extension back to xlsx.
So do this:
take the generated xlsx
change the extension to .zip
extract the files
find xl\worksheets\sheet1.xml
open it and find this property: worksheet>sheetViews>sheetView:tabSelected
set it to 0
save the file
go back to the unzipped folder
select all files and send to zip
change the extension on the new zip file to .xlsx
You should now be able to open the newly created xlsx, add a new sheet, and copy freely.
If this works for you, then you have diagnosed the problem, one property set to true when it shouldn't be, and it should be relatively simple for you to modify your export procedure.
I've had this issue multiple times in the past.
The way I solved it was by filling out (populating) a template (file, previously created in Office) with the exported data rather than generating a file from scratch. Office unfortunately does not fully comply with OpenXML, and for more complex exports you might even be unable to open the file.
I would also recommend Beyond Compare (now Scooter Software) for comparing the two files instead of just doing a diff.

How do you make a specific folder that has subfolders to be uneditable in Sublime Text

How do you make a specific folder that has subfolders to be uneditable in Sublime text? ? I know it's possible but how ? Like i have some old projects that I want to use as a reference to study my old code, but i"m worried that I mistakenly edited some parts of that specific module / file, when I'm mindlessly touring around my code.. How do I do it ? like making a specific folder to be uneditable in sublime text that only modifying it can change it . I mean I tried installing this one package : https://packagecontrol.io/packages/Toggle%20Read-Only
But it still gives me a prompt whenever I want to changed something from a file
Your best bet is to make sure that your source code is covered by some sort of Source Control, such as git or Subversion; this is just always a good idea in general and unrelated to your particular question. Having your code under source control means that when you edit a file (accidentally or on purpose) you can see exactly what you edited or throw those edits away and go back to what you had if you want to. If you also push your code to an external server, such as GitHUb (if you use git) then you also have a cheap and easy off-site backup of your code as well.
That said, if you want to make files uneditable, that's more the job of your file system than the tools that you're using to edit the files (in this case Sublime Text).
All file systems and operating systems should have the concept of a read-only file, which sounds like what you want. A file being marked as read-only stops you from accidentally modifying it; depending on the software that you use, edits are either impossible or will need to be confirmed.
In your case, you can do this in a couple of different ways. If you only want to protect a couple of files, then you would do a Right click and choose Properties; in the bottom of the General tab there is a check box you can check to make that file read-only:
If you have many files, you can do the same thing by editing the properties of the folder that contains the code instead:
When you do this to a folder, the property set works a little differently; since you're modifying the folder as a whole, you need to click the box twice to change it from a square (shown above) to a check mark. When you apply the change, you will be asked if you only want to make files inside of that directory read-only, or all files in that folder as well as all folders under it; choose as appropriate.
Sublime will let you open read-only files and will also let you modify their contents, but when you try to save you will get a warning dialog telling you that the file is write-protected; you need to confirm if you want to actually save changes or not; (other software may not prompt with such a dialog and may just fail):
If you choose to save, you will remove the read-only attribute and make the file normal again.
If you want to make a file completely un-editable so that you can't even accidentally change the file, you can achieve that with a simple plugin in combination with making the file read-only (see this video if you're not sure how to apply a plugin):
import sublime
import sublime_plugin
import os
class ReadOnlyListener(sublime_plugin.EventListener):
def on_load(self, view):
if (os.path.exists(view.file_name())
and not os.access(view.file_name(), os.W_OK)):
view.set_read_only(True)
EDIT: The internal View Package Files command will open package resources from sublime-package files transparently and give them a filename that represents where they would exist on disk if they were not in the package file.
The plugin from the original answer would stop you from being able to use this command by noting that the file is not writable (because it does not exist on disk) and make the view read-only, which stops the file content from being displayed because the view can't be modified.
This is rectified in the edit above by only taking action if the file actually exists on disk (the View Package File command already makes files it loads in this manner read-only if they do not exist on disk).
This makes an event listener that checks every time you open a file to see if the file is writable, and if it's not it makes the view read-only. This distinction is Sublime specific; regardless of the underlying state of the file, you just can't make any changes to such a file at all. That doesn't stop you from saving the file even if you haven't made any changes, which would have the same effect as the above.

How to notify the editor about document changes

I work on a custom project system and I have an issue with renaming items. The project system implementation is based on MPF and renaming items via the solution explorer worked more or less without any problems, but...
When an item gets renamed, I also update information which are stored in the file itself. In case the document is opened by the code editor, the text in the editor doesn´t get refreshed (only the document window´s caption changes to the new filename). If I save the open document all changes applied by the rename operation are overriden, of course.
How can I force the editor to reload the document, so that the automatic changes will be shown?
Assuming it's a text file versus some custom designer, use the IVsRunningDocumentTable interfaces to get the text buffer for the file that's currently open. The fourth iteration of the interface is the easiest one to use from managed code. You can call IsMonikerValid (where the "moniker" is the file name) to see if the file is open, and if so then call GetDocumentData to get the IVsTextBuffer for the file. That type itself is fairly annoying to work with, so if you're only supporting Visual Studio 2010 or later, then pass that to this function to get the newer editor APIs version of it.
As far as they "why" it's a good idea to do this: if you edit the file on disk and then try to force a reload, there are various problems you might run into. If the file wasn't saved before the rename, you might accidentally lose those unsaved edits. The reload might cause the undo history of the file to be lost, and any other extensions/features that were tracking points in the file with editor tracking spans or markers might lose the points they're tracking. Performance should be a bit better too if the file is a large file.

Matlab: open files 'outside Matlab' by default

I'm looking for a way to have Excel files in my Matlab folder open 'outside Matlab' (i.e., by MS Excel in most cases) directly by double-clicking the file, rather than right-clicking and selecting 'Open Outside Matlab'.
The .xls files reader built in Matlab can be terribly slow for large files, and an unwanted double-click on a file can cost quite some time in which Matlab is unresponsive.
Thanks.
When you click something in the Current Folder tab, it's actually running the open command, which itself calls finfo to determine what it means by "open" for a given extension. You can see this by creating a breakpoint in open.m directly after the line [~, openAction] = finfo(fullpath); and double clicking - when it hits the breakpoint you'll see it returns openAction as uiimport.
In theory, you can create custom methods for extensions by creating on the path a function openabc where abc is the extension, which should be returned as the openAction.
However, if I look at my finfo.m it first searches for said functions and then regardless of whether or not it finds them if there is an inbuilt method it overwrites them with the standard behaviour. There's even a comment:
% this setup will not allow users to override the default EXTread behavior
If you are willing to muck about in the inbuilts, you may be able to do it like this (backup first! - this could affect other things). I did it temporarily by shadowing the existing finfo like this:
edit finfo.m (Now save a copy to the current folder)
Add these lines after the loop that defines the openAction (in my version, around line 85):
if any(strcmp(['.' ext], matlab.io.internal.xlsreadSupportedExtensions))
openAction = 'winopen';
end
From the folder containing your edited finfo.m, type which finfo -all. You should see two copies, the MATLAB one labelled as shadowed. Opening something from the current folder window should now open Excel externally.
I don't believe there's any straightforward way to do that. It's built in to MATLAB that Excel files will open in the import tool when you double click on them, and there's no way to change that.
You might be able to get around it by changing the file extension on your Excel files to something other than .xls or .xlsx. That would stop MATLAB from opening it in the import tool. Then in Windows, you could associate the new file extension with Excel.

How could Visual Studio 2012 be set to use a custom tool to customise the Reading/writing of existing editors?

Update: It appears that VS doesn't have the hooks needed to do what is needed in my use case. However there are a couple of options that could work for other people and as such I'm marking the question as answered but I would love to find a solution that works for me.
We have encrypted files that are routinely kept in encrypted form within source control (TFS). When I want to compare versions I use Beyond Compare and have added the encryption/decryption tool as filtering on the read/write process to allow plain text viewing and editing.
However if I just want to open the file for reading/editing it's a bit tedious using a dummy comparison just to view/edit the file.
As such as I wondering if there is a configuration setting or way in Visual Studio that would allow me to insert a filter on the read/write so that it could display/edit/save files that would otherwise be unreadable.
Edit:
*NB: The encryption aspect is just single use case *, I'm actually looking for a generic answer that doesn't require writing an editor to replace the editors within VS that already exist such as the MS supplied XML editor or the custom third party ones.
I have both custom and non custom files that are encrypted. Each file type already has an editor. We have no access to the source for any of these editors. The problem is that the file is encrypted in TFS, and all I need is the filtering on the read and write for all files regardless of editor.
I want to use all the existing features of the installed editors without change. Only the reading and writing need to be customised.
Here's a potentially hacky way to achieve what you are trying to do, if there is no other easy option.
TFS stores data in a SQL database. Therefore you can theoretically modify the read/edit command that is used to extract the data from TFS and send it to the editor/viewer. This might involve modifying a stored procedure, or putting a trigger in place to modify the data before it is presented to the editor.
You would need to run a Profiler Trace on the TFS database when you click on edit/view or browse to the node in the source control tree. This will help you to figure out what data TFS is accessing and what functions/stored procs/tables etc it used to extract said data.
The same in reverse; you'd need to modify the 'writing' of the data to use your custom tool before putting it in the DB.
SQL has the ability to call CLR code, so you could use your tool if it's written in .NET.
The easiest way would be to download the 2012 SDK, Microsoft already provide a nice walkthrough on how to implement your custom editor HERE.
The process is:
Install the SDK
Fire up VS2012; Select New Project -> Other Proj Types -> Visual Studio Package
Visual C#, company name, etc...
Tick the "Custom Editor" tickbox
Fill in the rest of the details
So now you're presented with all the source of a vanilla text editor, and the part you want to hook in to is the IPersistFileFormat::Load() and IPersistFileFormat::Save() functions found under EditorPane.cs and put your encryption/decryption routines in there, thus you'll be left with a text editor with a custom encrypted file format.
This may not do what you need, since you need to call third party exe. However this answer may be useful for others that have access to source code (or a dll or library).
You could write a file system filter that encrypts/ decrypts the data to and from disk. Note that the driver sits at the OS level, and is outside of Visual Studio.
From the MSDN article File Systems and File System Filter Drivers:
A file system filter driver intercepts requests targeted at a file system or another file system filter driver. By intercepting the request before it reaches its intended target, the filter driver can extend or replace functionality provided by the original target of the request. Examples of File Systems and File System Filter Drivers include anti-virus filters, backup agents, and encryption products.
See this Code Project article for a tutorial: File System Filter Driver Tutorial. The article does not show how to do encryption/ decryption, but shows how to get a simple driver up and running.
There are extensions that will capture events to the current window save for example and what turns out to be document load. ** This is not a custom editor **
check out the following two links:
http://msdn.microsoft.com/en-us/library/dd885244.aspx
and a fairly complete open source addin that works with files when saved (regardless of type)
https://bitbucket.org/s_cadwallader/codemaid/src/7cf1bf6108801f48b85e30d85e1646fbc73ba889/CodeMaid/Integration/Events/RunningDocumentTableEventListener.cs?at=default
which hooks the RDT table to extend the current environment. You would need to adjust from here of course but this should get you going in the right direction.

Resources