Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
daramkun committed Jan 26, 2020
1 parent 00f8657 commit f4cf666
Show file tree
Hide file tree
Showing 18 changed files with 882 additions and 1 deletion.
79 changes: 79 additions & 0 deletions LinesMeasure.Shared/FileLineCountHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace LinesMeasure
{
public static class FileLineCountHelper
{
public static int GetFileLineCount ( string filename )
{
byte [] buffer = new byte [ 4096 ];
int count = 1;
using ( Stream stream = File.Open ( filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete ) )
{
while ( stream.Position != stream.Length )
{
int read = stream.Read ( buffer, 0, 4096 );
for ( int i = 0; i < read; ++i )
{
byte data = buffer [ i ];
if ( data == ( byte ) '\n' )
++count;
}
}
}
return count;
}

// Original Source code from http://stackoverflow.com/a/6613967
public static bool IsText ( string fileName, int windowSize )
{
try
{
using ( var fileStream = File.OpenRead ( fileName ) )
{
var rawData = new byte [ windowSize ];
var text = new char [ windowSize ];
var isText = true;

var rawLength = fileStream.Read ( rawData, 0, rawData.Length );
fileStream.Seek ( 0, SeekOrigin.Begin );

Encoding encoding;

if ( rawData [ 0 ] == 0xef && rawData [ 1 ] == 0xbb && rawData [ 2 ] == 0xbf )
encoding = Encoding.UTF8;
else if ( rawData [ 0 ] == 0xfe && rawData [ 1 ] == 0xff )
encoding = Encoding.Unicode;
else if ( rawData [ 0 ] == 0 && rawData [ 1 ] == 0 && rawData [ 2 ] == 0xfe && rawData [ 3 ] == 0xff )
encoding = Encoding.UTF32;
else if ( rawData [ 0 ] == 0x2b && rawData [ 1 ] == 0x2f && rawData [ 2 ] == 0x76 )
encoding = Encoding.UTF7;
else
encoding = Encoding.Default;

using ( var streamReader = new StreamReader ( fileStream ) )
streamReader.Read ( text, 0, text.Length );

using ( var memoryStream = new MemoryStream () )
{
using ( var streamWriter = new StreamWriter ( memoryStream, encoding ) )
{
streamWriter.Write ( text );
streamWriter.Flush ();

var memoryBuffer = memoryStream.GetBuffer ();
for ( var i = 0; i < rawLength && isText; i++ )
isText = rawData [ i ] == memoryBuffer [ i ];
}
}

return isText;
}
}
catch { return false; }
}
}
}
16 changes: 16 additions & 0 deletions LinesMeasure.Shared/LinesMeasure.Shared.projitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>260e7679-aeb6-45d7-8661-476588828d19</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>LinesMeasure</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)FileLineCountHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Node.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Quicksort.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions LinesMeasure.Shared/LinesMeasure.Shared.shproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>260e7679-aeb6-45d7-8661-476588828d19</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="LinesMeasure.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
263 changes: 263 additions & 0 deletions LinesMeasure.Shared/Node.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LinesMeasure
{
public class Node : INotifyPropertyChanged, IComparable<Node>
{

public event PropertyChangedEventHandler PropertyChanged;
protected void PC ( string name ) { PropertyChanged?.Invoke ( this, new PropertyChangedEventArgs ( name ) ); }

public string Name { get; private set; }
public Node ParentNode { get; private set; }
public IList<Node> SubNodes { get; private set; } = new ObservableCollection<Node> ();
public virtual bool? IsChecked
{
get
{
if ( SubNodes.Count == 0 ) return false;

int trueNodes = 0, falseNodes = 0;
foreach ( var node in SubNodes )
{
bool? sub = node.IsChecked;
if ( sub == true )
++trueNodes;
else if ( sub == false )
++falseNodes;
}

if ( trueNodes == SubNodes.Count )
return true;
else if ( falseNodes == SubNodes.Count )
return false;
else
return null;
}
set
{
SetIsCheckedChildren ( value );
//SetIsCheckedParent ();
}
}

private void SetIsCheckedChildren ( bool? value )
{
foreach ( var node in SubNodes )
node.IsChecked = value;
PC ( nameof ( IsChecked ) );
}

protected void SetIsCheckedParent ()
{
Node node = this;
while ( node != null )
{
node?.PC ( nameof ( IsChecked ) );
node = node.ParentNode;
}
}

public virtual int Lines
{
get
{
int total = 0;
foreach ( Node n in SubNodes )
total += ( n.IsChecked != false ) ? n.Lines : 0;
return total;
}
}

protected void SetLinesParent ()
{
Node node = this;
while ( node != null )
{
node?.PC ( nameof ( Lines ) );
node = node.ParentNode;
}
}
public Node ( string name )
{
Name = name;
}

public override string ToString () => Name;

public int CompareTo ( Node other )
{
if ( other == null || ( !( this is FileNode ) && other is FileNode ) )
return -1;
else if ( ( this is FileNode ) && !( other is FileNode ) )
return 1;
return Name.CompareTo ( other.Name );
}

private static void Sort ( Node node )
{
foreach ( Node n in node.SubNodes )
Sort ( n );

if ( node.SubNodes.Count != 0 )
Quicksort.Sort ( node.SubNodes );
}

private static readonly string [] IgnoreDirectories = {
".vs", ".vscode", //< Visual Studio, Visual Studio Code
".idea", ".idea_modules", //< IntelliJ
".git", ".svn", //< Source Version Control
"bin", "obj", "res", //< Common Binary, Object, Resources directories
};
public static Node FilesToNode ( IEnumerable<string> pathes )
{
SpinLock spinLock = new SpinLock ();

Node node = new Node ( null );
Parallel.ForEach ( pathes, ( path ) =>
{
var split = path.Split ( '\\' );
Node root = node;
foreach ( string s in split )
{
if ( IgnoreDirectories.Contains ( s.ToLower () ) )
return;

bool proceed = false;

bool lockTaken = false;
do
{
spinLock.Enter ( ref lockTaken );
} while ( !lockTaken );
foreach ( Node n in root.SubNodes )
{
if ( n.Name == s )
{
root = n;
proceed = true;
}
}

if ( !proceed )
{
Node n = ( s == split [ split.Length - 1 ] && !File.GetAttributes ( path ).HasFlag ( FileAttributes.Directory ) )
? new FileNode ( s, path )
: new Node ( s );
n.ParentNode = root;

root.SubNodes.Add ( n );
root = n;
}
spinLock.Exit ();
}
} );

while ( node.SubNodes.Count == 1 )
{
node = node.SubNodes [ 0 ];
node.ParentNode = null;
}
Sort ( node );

return node;
}
}

public class FileNode : Node
{
private static readonly string [] SourceCodeExtensions = {
".cs", //< C#
".fs", ".cls", ".bas", ".vb", ".vbs", ".qs", //< F#, Visual Basic, Visual Basic.NET, Q#
".asp", ".aspx", ".asx", ".asmx", //< ASP/ASP.NET
".java", ".kt", //< Java, Kotlin
".jsp", ".jspx", ".do", //< JSP
".html", ".htm", ".xhtml", ".shtml", //< HTML
".css", //< CSS
".js", ".ts", //< Javascript, Typescript
".php", ".php3", ".phps", //< PHP
".cgi", //< C/Perl CGI
".cpp", ".h", ".hxx", ".hpp", ".c", ".hh", ".cc", ".cp", ".cxx", ".ixx", ".inl",//< C/C++
".asm", ".s", //< Assembly
".m", ".mm", //< Objective-C or MATLAB
".swift", //< Swift
".py", "pyx", //< Python
".rs", //< Rust
".lua", //< Lua
".pl", //< Perl
".go", //< Go
".rb", ".rhtml", ".erb", ".rjs", //< Ruby
".xml", //< XML
".coffee", "._coffee", ".cake", ".cjsx", ".iced", //< CoffeeScript
".erl", ".yaws", //< Erlang
".bash", ".sh", ".zsh", ".ps", ".ps1", ".bat", ".csh", //< Shell Scripts
".pas", ".dpr", ".lpr", //< Pascal
".lisp", ".lsp", ".mnl", //< LISP
".hlsl", ".glsl", ".fx", ".shaderlab", ".metal", ".vert", ".frag", ".tesc",
".tese", ".geom", ".comp", //< Shader Languages
".hs", //< Haskell
".gs", //< Google Apps Script
".groovy", //< Groovy
".ex", ".exs", //< Elixir
".scala", ".sc", //< Scala
".sml", //< Standard ML
".ml", ".mli", //< Ocaml
".scm", //< Scheme
".dart", //< Dart
".hx", //< Haxe
".r", //< R
".sql", //< SQL
".as", //< ActionScript
".clj", ".edn", //< Clojure
".nut", //< Squirrel
};

public string FullPath { get; private set; }

bool? isChecked = false;
public override bool? IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
PC ( nameof ( IsChecked ) );
SetIsCheckedParent ();
SetLinesParent ();
}
}

int lines = 0;
public override int Lines => lines;
public FileNode ( string name, string path )
: base ( name )
{
FullPath = path;
string ext = Path.GetExtension ( FullPath );
if ( SourceCodeExtensions.Contains ( ext ) && Path.GetFileName ( FullPath ) != "AssemblyInfo.cs" )
{
try
{
IsChecked = true;
lines = FileLineCountHelper.GetFileLineCount ( FullPath );
}
catch
{
IsChecked = false;
lines = 0;
}
}
}

public override string ToString () => $"{Name} ({FullPath})";
}
}
Loading

0 comments on commit f4cf666

Please sign in to comment.